Merge branch 'feature/delete-category' into 'master'
Add ability to delete a group See merge request framasoft/mobilizon!50
This commit is contained in:
commit
b6f905313a
|
@ -242,6 +242,13 @@ defmodule Mobilizon.Actors do
|
||||||
|> Repo.insert()
|
|> Repo.insert()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Delete a group
|
||||||
|
"""
|
||||||
|
def delete_group!(%Actor{type: :Group} = group) do
|
||||||
|
Repo.delete!(group)
|
||||||
|
end
|
||||||
|
|
||||||
alias Mobilizon.Actors.User
|
alias Mobilizon.Actors.User
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -551,6 +558,16 @@ defmodule Mobilizon.Actors do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Find a group by its actor id
|
||||||
|
"""
|
||||||
|
def find_group_by_actor_id(actor_id) do
|
||||||
|
case Repo.get_by(Actor, id: actor_id, type: :Group) do
|
||||||
|
nil -> {:error, :group_not_found}
|
||||||
|
actor -> {:ok, actor}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Authenticate user
|
Authenticate user
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -6,6 +6,7 @@ defmodule Mobilizon.Actors.Member do
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
alias Mobilizon.Actors.Member
|
alias Mobilizon.Actors.Member
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
|
alias Mobilizon.Repo
|
||||||
|
|
||||||
schema "members" do
|
schema "members" do
|
||||||
field(:approved, :boolean, default: true)
|
field(:approved, :boolean, default: true)
|
||||||
|
@ -24,4 +25,22 @@ defmodule Mobilizon.Actors.Member do
|
||||||
|> validate_required([:parent_id, :actor_id])
|
|> validate_required([:parent_id, :actor_id])
|
||||||
|> unique_constraint(:parent_id, name: :members_actor_parent_unique_index)
|
|> unique_constraint(:parent_id, name: :members_actor_parent_unique_index)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Gets a single member of an actor (for example a group)
|
||||||
|
"""
|
||||||
|
def get_member(actor_id, parent_id) do
|
||||||
|
case Repo.get_by(Member, actor_id: actor_id, parent_id: parent_id) do
|
||||||
|
nil -> {:error, :member_not_found}
|
||||||
|
member -> {:ok, member}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_administrator(%Member{role: 2} = member) do
|
||||||
|
{:is_admin, true}
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_administrator(%Member{}) do
|
||||||
|
{:is_admin, false}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -144,4 +144,16 @@ defmodule Mobilizon.Actors.User do
|
||||||
def is_confirmed(%User{} = user) do
|
def is_confirmed(%User{} = user) do
|
||||||
{:ok, user}
|
{:ok, user}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def owns_actor(%User{default_actor_id: default_actor_id} = user, %Actor{id: actor_id})
|
||||||
|
when default_actor_id == actor_id do
|
||||||
|
{:is_owned, true}
|
||||||
|
end
|
||||||
|
|
||||||
|
def owns_actor(%User{actors: actors} = user, actor_id) do
|
||||||
|
case Enum.any?(actors, fn a -> a.id == actor_id end) do
|
||||||
|
true -> {:is_owned, true}
|
||||||
|
_ -> {:is_owned, false}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ defmodule MobilizonWeb.Resolvers.Group do
|
||||||
Handles the group-related GraphQL calls
|
Handles the group-related GraphQL calls
|
||||||
"""
|
"""
|
||||||
alias Mobilizon.Actors
|
alias Mobilizon.Actors
|
||||||
alias Mobilizon.Actors.{Actor}
|
alias Mobilizon.Actors.{Actor, User, Member}
|
||||||
alias Mobilizon.Service.ActivityPub
|
alias Mobilizon.Service.ActivityPub
|
||||||
alias Mobilizon.Activity
|
alias Mobilizon.Activity
|
||||||
require Logger
|
require Logger
|
||||||
|
@ -68,4 +68,41 @@ defmodule MobilizonWeb.Resolvers.Group do
|
||||||
def create_group(_parent, _args, _resolution) do
|
def create_group(_parent, _args, _resolution) do
|
||||||
{:error, "You need to be logged-in to create a group"}
|
{:error, "You need to be logged-in to create a group"}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Delete an existing group
|
||||||
|
"""
|
||||||
|
def delete_group(
|
||||||
|
_parent,
|
||||||
|
%{group_id: group_id, actor_id: actor_id},
|
||||||
|
%{
|
||||||
|
context: %{
|
||||||
|
current_user: user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) do
|
||||||
|
with {:ok, %Actor{} = group} <- Actors.find_group_by_actor_id(group_id),
|
||||||
|
{:is_owned, true} <- User.owns_actor(user, actor_id),
|
||||||
|
{:ok, %Member{} = member} <- Member.get_member(actor_id, group.id),
|
||||||
|
{:is_admin, true} <- Member.is_administrator(member),
|
||||||
|
group <- Actors.delete_group!(group) do
|
||||||
|
{:ok, %{id: group.id}}
|
||||||
|
else
|
||||||
|
{:error, :group_not_found} ->
|
||||||
|
{:error, "Group with preferred username not found"}
|
||||||
|
|
||||||
|
{:is_owned, false} ->
|
||||||
|
{:error, "Actor id is not owned by authenticated user"}
|
||||||
|
|
||||||
|
{:error, :member_not_found} ->
|
||||||
|
{:error, "Actor id is not a member of this group"}
|
||||||
|
|
||||||
|
{:is_admin, false} ->
|
||||||
|
{:error, "User is not an administrator of the selected group"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_group(_parent, _args, _resolution) do
|
||||||
|
{:error, "You need to be logged-in to delete a group"}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,6 +20,11 @@ defmodule MobilizonWeb.Schema do
|
||||||
|
|
||||||
alias MobilizonWeb.Resolvers
|
alias MobilizonWeb.Resolvers
|
||||||
|
|
||||||
|
@desc "A struct containing the id of the deleted object"
|
||||||
|
object :deleted_object do
|
||||||
|
field(:id, :integer)
|
||||||
|
end
|
||||||
|
|
||||||
@desc "A JWT and the associated user ID"
|
@desc "A JWT and the associated user ID"
|
||||||
object :login do
|
object :login do
|
||||||
field(:token, non_null(:string), description: "A JWT Token for this session")
|
field(:token, non_null(:string), description: "A JWT Token for this session")
|
||||||
|
@ -301,6 +306,14 @@ defmodule MobilizonWeb.Schema do
|
||||||
resolve(&Resolvers.Group.create_group/3)
|
resolve(&Resolvers.Group.create_group/3)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@desc "Delete a group"
|
||||||
|
field :delete_group, :deleted_object do
|
||||||
|
arg(:group_id, non_null(:integer))
|
||||||
|
arg(:actor_id, non_null(:integer))
|
||||||
|
|
||||||
|
resolve(&Resolvers.Group.delete_group/3)
|
||||||
|
end
|
||||||
|
|
||||||
# @desc "Upload a picture"
|
# @desc "Upload a picture"
|
||||||
# field :upload_picture, :picture do
|
# field :upload_picture, :picture do
|
||||||
# arg(:file, non_null(:upload))
|
# arg(:file, non_null(:upload))
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
defmodule Mobilizon.Repo.Migrations.GroupDeleteMembersCascade do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
drop constraint(:members, "members_account_id_fkey")
|
||||||
|
drop constraint(:members, "members_parent_id_fkey")
|
||||||
|
|
||||||
|
alter table(:members) do
|
||||||
|
modify :actor_id, references(:actors, on_delete: :delete_all)
|
||||||
|
modify :parent_id, references(:actors, on_delete: :delete_all)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -114,5 +114,36 @@ defmodule MobilizonWeb.Resolvers.GroupResolverTest do
|
||||||
assert hd(json_response(res, 200)["errors"])["message"] ==
|
assert hd(json_response(res, 200)["errors"])["message"] ==
|
||||||
"Group with name #{@non_existent_username} not found"
|
"Group with name #{@non_existent_username} not found"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "delete_group/3 deletes a group", %{conn: conn, user: user, actor: actor} do
|
||||||
|
group = insert(:group)
|
||||||
|
insert(:member, parent: group, actor: actor, role: 2)
|
||||||
|
|
||||||
|
mutation = """
|
||||||
|
mutation {
|
||||||
|
deleteGroup(
|
||||||
|
actor_id: #{actor.id},
|
||||||
|
group_id: #{group.id}
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
|
||||||
|
|
||||||
|
assert json_response(res, 200)["errors"] == nil
|
||||||
|
assert json_response(res, 200)["data"]["deleteGroup"]["id"] == group.id
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
|
||||||
|
|
||||||
|
assert hd(json_response(res, 200)["errors"])["message"] =~ "not found"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -148,7 +148,8 @@ defmodule Mobilizon.Factory do
|
||||||
def member_factory do
|
def member_factory do
|
||||||
%Mobilizon.Actors.Member{
|
%Mobilizon.Actors.Member{
|
||||||
parent: build(:actor),
|
parent: build(:actor),
|
||||||
actor: build(:actor)
|
actor: build(:actor),
|
||||||
|
role: 0
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue