2020-01-26 20:34:25 +01:00
|
|
|
|
defmodule Mobilizon.GraphQL.Resolvers.Group do
|
2019-01-03 14:59:59 +01:00
|
|
|
|
@moduledoc """
|
2019-09-22 16:26:23 +02:00
|
|
|
|
Handles the group-related GraphQL calls.
|
2019-01-03 14:59:59 +01:00
|
|
|
|
"""
|
2019-09-22 16:26:23 +02:00
|
|
|
|
|
2020-08-27 11:53:24 +02:00
|
|
|
|
import Mobilizon.Users.Guards
|
2020-02-18 08:57:00 +01:00
|
|
|
|
alias Mobilizon.{Actors, Events, Users}
|
2019-03-05 17:23:05 +01:00
|
|
|
|
alias Mobilizon.Actors.{Actor, Member}
|
2020-02-18 08:57:00 +01:00
|
|
|
|
alias Mobilizon.Federation.ActivityPub
|
2020-01-26 21:11:16 +01:00
|
|
|
|
alias Mobilizon.GraphQL.API
|
2020-01-26 20:34:25 +01:00
|
|
|
|
alias Mobilizon.GraphQL.Resolvers.Person
|
2020-02-18 08:57:00 +01:00
|
|
|
|
alias Mobilizon.Users.User
|
2020-01-22 02:14:42 +01:00
|
|
|
|
|
2018-12-03 11:58:57 +01:00
|
|
|
|
require Logger
|
|
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
|
@doc """
|
|
|
|
|
Find a group
|
|
|
|
|
"""
|
|
|
|
|
def find_group(
|
|
|
|
|
parent,
|
|
|
|
|
%{preferred_username: name} = args,
|
|
|
|
|
%{
|
|
|
|
|
context: %{
|
|
|
|
|
current_user: %User{} = user
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
) do
|
|
|
|
|
with {:ok, %Actor{id: group_id} = group} <-
|
|
|
|
|
ActivityPub.find_or_make_group_from_nickname(name),
|
|
|
|
|
{:actor, %Actor{id: actor_id} = _actor} <- {:actor, Users.get_actor_for_user(user)},
|
|
|
|
|
{:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
|
|
|
|
group <- Person.proxify_pictures(group) do
|
|
|
|
|
{:ok, group}
|
|
|
|
|
else
|
|
|
|
|
{:member, false} ->
|
|
|
|
|
find_group(parent, args, nil)
|
|
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
|
{:error, "Group with name #{name} not found"}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2018-12-03 11:58:57 +01:00
|
|
|
|
@doc """
|
|
|
|
|
Find a group
|
|
|
|
|
"""
|
|
|
|
|
def find_group(_parent, %{preferred_username: name}, _resolution) do
|
2019-05-28 10:51:02 +02:00
|
|
|
|
with {:ok, actor} <- ActivityPub.find_or_make_group_from_nickname(name),
|
2020-02-18 08:57:00 +01:00
|
|
|
|
%Actor{} = actor <- Person.proxify_pictures(actor),
|
|
|
|
|
%Actor{} = actor <- restrict_fields_for_non_member_request(actor) do
|
2019-05-28 10:51:02 +02:00
|
|
|
|
{:ok, actor}
|
|
|
|
|
else
|
2018-12-03 11:58:57 +01:00
|
|
|
|
_ ->
|
|
|
|
|
{:error, "Group with name #{name} not found"}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2020-08-27 11:53:24 +02:00
|
|
|
|
@doc """
|
|
|
|
|
Get a group
|
|
|
|
|
"""
|
|
|
|
|
def get_group(_parent, %{id: id}, %{context: %{current_user: %User{role: role}}}) do
|
|
|
|
|
with %Actor{type: :Group, suspended: suspended} = actor <-
|
|
|
|
|
Actors.get_actor_with_preload(id, true),
|
|
|
|
|
true <- suspended == false or is_moderator(role) do
|
|
|
|
|
{:ok, actor}
|
|
|
|
|
else
|
|
|
|
|
_ ->
|
|
|
|
|
{:error, "Group with ID #{id} not found"}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2018-12-03 11:58:57 +01:00
|
|
|
|
@doc """
|
|
|
|
|
Lists all groups
|
|
|
|
|
"""
|
2020-08-27 11:53:24 +02:00
|
|
|
|
def list_groups(
|
|
|
|
|
_parent,
|
|
|
|
|
%{
|
|
|
|
|
preferred_username: preferred_username,
|
|
|
|
|
name: name,
|
|
|
|
|
domain: domain,
|
|
|
|
|
local: local,
|
|
|
|
|
suspended: suspended,
|
|
|
|
|
page: page,
|
|
|
|
|
limit: limit
|
|
|
|
|
},
|
|
|
|
|
%{
|
|
|
|
|
context: %{current_user: %User{role: role}}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
when is_moderator(role) do
|
|
|
|
|
{:ok,
|
|
|
|
|
Actors.list_actors(:Group, preferred_username, name, domain, local, suspended, page, limit)}
|
2018-12-03 11:58:57 +01:00
|
|
|
|
end
|
|
|
|
|
|
2020-08-27 11:53:24 +02:00
|
|
|
|
def list_groups(_parent, _args, _resolution),
|
|
|
|
|
do: {:error, "You may not list groups unless moderator."}
|
|
|
|
|
|
2018-12-03 11:58:57 +01:00
|
|
|
|
@doc """
|
|
|
|
|
Create a new group. The creator is automatically added as admin
|
|
|
|
|
"""
|
2020-02-18 08:57:00 +01:00
|
|
|
|
def create_group(
|
|
|
|
|
_parent,
|
|
|
|
|
args,
|
|
|
|
|
%{
|
|
|
|
|
context: %{
|
|
|
|
|
current_user: user
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
) do
|
2019-10-25 17:43:37 +02:00
|
|
|
|
with creator_actor_id <- Map.get(args, :creator_actor_id),
|
2019-12-03 11:29:51 +01:00
|
|
|
|
{:is_owned, %Actor{} = creator_actor} <- User.owns_actor(user, creator_actor_id),
|
|
|
|
|
args <- Map.put(args, :creator_actor, creator_actor),
|
2019-10-25 17:43:37 +02:00
|
|
|
|
{:ok, _activity, %Actor{type: :Group} = group} <-
|
|
|
|
|
API.Groups.create_group(args) do
|
2019-09-07 19:54:11 +02:00
|
|
|
|
{:ok, group}
|
2019-10-25 17:43:37 +02:00
|
|
|
|
else
|
2020-07-09 17:24:28 +02:00
|
|
|
|
{:error, err} when is_binary(err) ->
|
2019-10-25 17:43:37 +02:00
|
|
|
|
{:error, err}
|
|
|
|
|
|
|
|
|
|
{:is_owned, nil} ->
|
|
|
|
|
{:error, "Creator actor id is not owned by the current user"}
|
2018-12-03 11:58:57 +01:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def create_group(_parent, _args, _resolution) do
|
|
|
|
|
{:error, "You need to be logged-in to create a group"}
|
|
|
|
|
end
|
2019-01-25 09:23:44 +01:00
|
|
|
|
|
2020-07-09 17:24:28 +02:00
|
|
|
|
@doc """
|
|
|
|
|
Create a new group. The creator is automatically added as admin
|
|
|
|
|
"""
|
|
|
|
|
def update_group(
|
|
|
|
|
_parent,
|
|
|
|
|
args,
|
|
|
|
|
%{
|
|
|
|
|
context: %{
|
|
|
|
|
current_user: %User{} = user
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
) do
|
|
|
|
|
with %Actor{} = updater_actor <- Users.get_actor_for_user(user),
|
|
|
|
|
args <- Map.put(args, :updater_actor, updater_actor),
|
|
|
|
|
{:ok, _activity, %Actor{type: :Group} = group} <-
|
|
|
|
|
API.Groups.update_group(args) do
|
|
|
|
|
{:ok, group}
|
|
|
|
|
else
|
|
|
|
|
{:error, err} when is_binary(err) ->
|
|
|
|
|
{:error, err}
|
|
|
|
|
|
|
|
|
|
{:is_owned, nil} ->
|
|
|
|
|
{:error, "Creator actor id is not owned by the current user"}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def update_group(_parent, _args, _resolution) do
|
|
|
|
|
{:error, "You need to be logged-in to update a group"}
|
|
|
|
|
end
|
|
|
|
|
|
2019-01-25 09:23:44 +01:00
|
|
|
|
@doc """
|
|
|
|
|
Delete an existing group
|
|
|
|
|
"""
|
|
|
|
|
def delete_group(
|
|
|
|
|
_parent,
|
2020-08-27 11:53:24 +02:00
|
|
|
|
%{group_id: group_id},
|
2020-02-18 08:57:00 +01:00
|
|
|
|
%{
|
|
|
|
|
context: %{
|
|
|
|
|
current_user: user
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-25 09:23:44 +01:00
|
|
|
|
) do
|
2020-08-27 11:53:24 +02:00
|
|
|
|
with %Actor{id: actor_id} = actor <- Users.get_actor_for_user(user),
|
2019-09-09 09:31:08 +02:00
|
|
|
|
{:ok, %Actor{} = group} <- Actors.get_group_by_actor_id(group_id),
|
2019-09-09 00:52:49 +02:00
|
|
|
|
{:ok, %Member{} = member} <- Actors.get_member(actor_id, group.id),
|
2020-02-18 08:57:00 +01:00
|
|
|
|
{:is_admin, true} <- {:is_admin, Member.is_administrator(member)},
|
2020-08-27 11:53:24 +02:00
|
|
|
|
{:ok, _activity, group} <- ActivityPub.delete(group, actor, true) do
|
2019-01-25 09:23:44 +01:00
|
|
|
|
{:ok, %{id: group.id}}
|
|
|
|
|
else
|
|
|
|
|
{:error, :group_not_found} ->
|
2019-01-25 17:06:57 +01:00
|
|
|
|
{:error, "Group not found"}
|
2019-01-25 09:23:44 +01:00
|
|
|
|
|
|
|
|
|
{:error, :member_not_found} ->
|
|
|
|
|
{:error, "Actor id is not a member of this group"}
|
|
|
|
|
|
|
|
|
|
{:is_admin, false} ->
|
2019-02-01 09:42:31 +01:00
|
|
|
|
{:error, "Actor id is not an administrator of the selected group"}
|
2019-01-25 09:23:44 +01:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def delete_group(_parent, _args, _resolution) do
|
|
|
|
|
{:error, "You need to be logged-in to delete a group"}
|
|
|
|
|
end
|
2019-03-01 17:11:28 +01:00
|
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
|
Join an existing group
|
|
|
|
|
"""
|
|
|
|
|
def join_group(
|
|
|
|
|
_parent,
|
|
|
|
|
%{group_id: group_id, actor_id: actor_id},
|
2020-02-18 08:57:00 +01:00
|
|
|
|
%{
|
|
|
|
|
context: %{
|
|
|
|
|
current_user: user
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-01 17:11:28 +01:00
|
|
|
|
) do
|
2019-09-09 09:31:08 +02:00
|
|
|
|
with {actor_id, ""} <- Integer.parse(actor_id),
|
|
|
|
|
{group_id, ""} <- Integer.parse(group_id),
|
2019-09-21 23:59:07 +02:00
|
|
|
|
{:is_owned, %Actor{} = actor} <- User.owns_actor(user, actor_id),
|
2019-03-01 17:11:28 +01:00
|
|
|
|
{:ok, %Actor{} = group} <- Actors.get_group_by_actor_id(group_id),
|
2019-09-09 00:52:49 +02:00
|
|
|
|
{:error, :member_not_found} <- Actors.get_member(actor.id, group.id),
|
2019-03-01 17:11:28 +01:00
|
|
|
|
{:is_able_to_join, true} <- {:is_able_to_join, Member.can_be_joined(group)},
|
2019-09-09 00:52:49 +02:00
|
|
|
|
role <- Member.get_default_member_role(group),
|
2019-09-07 19:54:11 +02:00
|
|
|
|
{:ok, _} <- Actors.create_member(%{parent_id: group.id, actor_id: actor.id, role: role}) do
|
2019-09-02 10:50:00 +02:00
|
|
|
|
{
|
|
|
|
|
:ok,
|
|
|
|
|
%{
|
2019-09-07 19:54:11 +02:00
|
|
|
|
parent: Person.proxify_pictures(group),
|
|
|
|
|
actor: Person.proxify_pictures(actor),
|
2019-09-02 10:50:00 +02:00
|
|
|
|
role: role
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-01 17:11:28 +01:00
|
|
|
|
else
|
2019-09-07 19:54:11 +02:00
|
|
|
|
{:is_owned, nil} ->
|
2019-03-01 17:11:28 +01:00
|
|
|
|
{:error, "Actor id is not owned by authenticated user"}
|
|
|
|
|
|
|
|
|
|
{:error, :group_not_found} ->
|
|
|
|
|
{:error, "Group id not found"}
|
|
|
|
|
|
|
|
|
|
{:is_able_to_join, false} ->
|
|
|
|
|
{:error, "You cannot join this group"}
|
|
|
|
|
|
|
|
|
|
{:ok, %Member{}} ->
|
|
|
|
|
{:error, "You are already a member of this group"}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def join_group(_parent, _args, _resolution) do
|
|
|
|
|
{:error, "You need to be logged-in to join a group"}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
|
Leave a existing group
|
|
|
|
|
"""
|
|
|
|
|
def leave_group(
|
|
|
|
|
_parent,
|
2020-08-14 11:32:23 +02:00
|
|
|
|
%{group_id: group_id},
|
2020-02-18 08:57:00 +01:00
|
|
|
|
%{
|
|
|
|
|
context: %{
|
2020-08-14 11:32:23 +02:00
|
|
|
|
current_user: %User{} = user
|
2020-02-18 08:57:00 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-01 17:11:28 +01:00
|
|
|
|
) do
|
2020-08-14 11:32:23 +02:00
|
|
|
|
with {:actor, %Actor{} = actor} <- {:actor, Users.get_actor_for_user(user)},
|
|
|
|
|
{:group, %Actor{type: :Group} = group} <- {:group, Actors.get_actor(group_id)},
|
|
|
|
|
{:ok, _activity, %Member{} = member} <- ActivityPub.leave(group, actor, true) do
|
|
|
|
|
{:ok, member}
|
2019-03-01 17:11:28 +01:00
|
|
|
|
else
|
|
|
|
|
{:error, :member_not_found} ->
|
|
|
|
|
{:error, "Member not found"}
|
|
|
|
|
|
2020-08-14 11:32:23 +02:00
|
|
|
|
{:group, nil} ->
|
|
|
|
|
{:error, "Group not found"}
|
|
|
|
|
|
2020-08-27 11:53:24 +02:00
|
|
|
|
{:is_not_only_admin, false} ->
|
2019-03-01 17:11:28 +01:00
|
|
|
|
{:error, "You can't leave this group because you are the only administrator"}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def leave_group(_parent, _args, _resolution) do
|
|
|
|
|
{:error, "You need to be logged-in to leave a group"}
|
|
|
|
|
end
|
|
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
|
def find_events_for_group(
|
|
|
|
|
%Actor{id: group_id} = group,
|
2020-09-02 17:42:17 +02:00
|
|
|
|
%{
|
|
|
|
|
page: page,
|
|
|
|
|
limit: limit
|
|
|
|
|
} = args,
|
2020-02-18 08:57:00 +01:00
|
|
|
|
%{
|
|
|
|
|
context: %{
|
2020-08-27 11:53:24 +02:00
|
|
|
|
current_user: %User{role: user_role} = user
|
2020-02-18 08:57:00 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
) do
|
|
|
|
|
with {:actor, %Actor{id: actor_id} = _actor} <- {:actor, Users.get_actor_for_user(user)},
|
2020-08-27 11:53:24 +02:00
|
|
|
|
{:member, true} <-
|
|
|
|
|
{:member, Actors.is_member?(actor_id, group_id) or is_moderator(user_role)} do
|
2020-02-18 08:57:00 +01:00
|
|
|
|
# TODO : Handle public / restricted to group members events
|
2020-09-02 17:42:17 +02:00
|
|
|
|
{:ok,
|
|
|
|
|
Events.list_organized_events_for_group(
|
|
|
|
|
group,
|
|
|
|
|
:all,
|
|
|
|
|
Map.get(args, :after_datetime),
|
|
|
|
|
Map.get(args, :before_datetime),
|
|
|
|
|
page,
|
|
|
|
|
limit
|
|
|
|
|
)}
|
2020-02-18 08:57:00 +01:00
|
|
|
|
else
|
|
|
|
|
{:member, false} ->
|
2020-09-02 17:42:17 +02:00
|
|
|
|
find_events_for_group(group, args, nil)
|
2020-02-18 08:57:00 +01:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2020-09-02 17:42:17 +02:00
|
|
|
|
def find_events_for_group(
|
|
|
|
|
%Actor{} = group,
|
|
|
|
|
%{
|
|
|
|
|
page: page,
|
|
|
|
|
limit: limit
|
|
|
|
|
} = args,
|
|
|
|
|
_resolution
|
|
|
|
|
) do
|
|
|
|
|
{:ok,
|
|
|
|
|
Events.list_organized_events_for_group(
|
|
|
|
|
group,
|
|
|
|
|
:public,
|
|
|
|
|
Map.get(args, :after_datetime),
|
|
|
|
|
Map.get(args, :before_datetime),
|
|
|
|
|
page,
|
|
|
|
|
limit
|
|
|
|
|
)}
|
2020-02-18 08:57:00 +01:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp restrict_fields_for_non_member_request(%Actor{} = group) do
|
|
|
|
|
Map.merge(
|
|
|
|
|
group,
|
|
|
|
|
%{
|
|
|
|
|
followers: [],
|
|
|
|
|
followings: [],
|
|
|
|
|
organized_events: [],
|
|
|
|
|
comments: [],
|
|
|
|
|
feed_tokens: []
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
end
|
2018-12-03 11:58:57 +01:00
|
|
|
|
end
|