Introduce basic user and profile management

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2020-06-11 19:13:21 +02:00
parent da4ea84baf
commit beb35a09c6
51 changed files with 1808 additions and 254 deletions

View File

@@ -12,9 +12,8 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
import ExUnit.CaptureLog
import Mock
alias Mobilizon.{Actors, Conversations, Events, Resources, Tombstone}
alias Mobilizon.{Actors, Conversations, Events}
alias Mobilizon.Actors.{Actor, Member}
alias Mobilizon.Collections.Resource
alias Mobilizon.Conversations.Comment
alias Mobilizon.Events.{Event, Participant}
alias Mobilizon.Resources.Resource
@@ -557,7 +556,6 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
assert is_nil(resource.parent_id)
end
@parent_url "http://mobilizon1.com/resource/e4ce71bd-6bcc-4c61-9774-7999dde0cc68"
test "it accepts incoming resources that are in a folder" do
creator =
insert(:actor,
@@ -978,12 +976,13 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
{:ok, _activity, _actor} = Transmogrifier.handle_incoming(data)
assert %{success: 1, failure: 0} == Oban.drain_queue(:background)
assert {:ok, %Actor{suspended: true}} = Actors.get_actor_by_url(url)
assert {:error, :actor_not_found} = Actors.get_actor_by_url(url)
assert {:error, :event_not_found} = Events.get_event(event1.id)
assert %Tombstone{} = Tombstone.find_tombstone(event1_url)
# Tombstone are cascade deleted, seems correct for now
# assert %Tombstone{} = Tombstone.find_tombstone(event1_url)
assert %Comment{deleted_at: deleted_at} = Conversations.get_comment(comment1.id)
refute is_nil(deleted_at)
assert %Tombstone{} = Tombstone.find_tombstone(comment1_url)
# assert %Tombstone{} = Tombstone.find_tombstone(comment1_url)
end
test "it fails for incoming actor deletes with spoofed origin" do

View File

@@ -273,16 +273,18 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
person(id: $actor_id) {
id,
participations(eventId: $event_id) {
id,
role,
actor {
id
},
event {
id
elements {
id,
role,
actor {
id
},
event {
id
}
}
}
}
}
}
"""
@@ -295,7 +297,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
)
assert res["errors"] == nil
assert res["data"]["person"]["participations"] == []
assert res["data"]["person"]["participations"]["elements"] == []
end
test "create_event/3 creates an event with options", %{conn: conn, actor: actor, user: user} do
@@ -979,16 +981,18 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
person(id: "#{actor.id}") {
id,
participations(eventId: #{event.id}) {
id,
role,
actor {
id
},
event {
id
elements {
id,
role,
actor {
id
},
event {
id
}
}
}
}
}
}
"""
@@ -998,7 +1002,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
|> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["person"]["participations"] == []
assert json_response(res, 200)["data"]["person"]["participations"]["elements"] == []
mutation = """
mutation {
@@ -1042,15 +1046,17 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
person(id: "#{actor.id}") {
id,
participations(eventId: #{event.id}) {
role,
actor {
id
},
event {
id
elements {
role,
actor {
id
},
event {
id
}
}
}
}
}
}
"""
@@ -1061,7 +1067,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["person"]["participations"] == [
assert json_response(res, 200)["data"]["person"]["participations"]["elements"] == [
%{
"actor" => %{"id" => to_string(actor.id)},
"event" => %{"id" => to_string(event.id)},

View File

@@ -201,6 +201,23 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do
"Event with this ID \"1042\" doesn't exist"
end
@person_participations """
query PersonParticipations($actorId: ID!, $eventId: ID) {
person(id: $actorId) {
participations(eventId: $eventId) {
total,
elements {
event {
uuid,
title
},
role
}
}
}
}
"""
test "actor_leave_event/3 should delete a participant from an event", %{
conn: conn,
user: user,
@@ -241,26 +258,15 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do
assert json_response(res, 200)["data"]["leaveEvent"]["actor"]["id"] ==
to_string(participant2.actor.id)
query = """
{
person(id: "#{actor.id}") {
participations(eventId: "#{event.id}") {
event {
uuid,
title
},
role
}
}
}
"""
res =
conn
|> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
|> AbsintheHelpers.graphql_query(
query: @person_participations,
variables: %{actorId: actor.id, eventId: event.id}
)
assert json_response(res, 200)["data"]["person"]["participations"] == [
assert res["data"]["person"]["participations"]["elements"] == [
%{
"event" => %{
"uuid" => event.uuid,
@@ -270,26 +276,15 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do
}
]
query = """
{
person(id: "#{actor2.id}") {
participations(eventId: "#{event.id}") {
event {
uuid,
title
},
role
}
}
}
"""
res =
conn
|> auth_conn(user2)
|> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
|> AbsintheHelpers.graphql_query(
query: @person_participations,
variables: %{actorId: actor2.id, eventId: event.id}
)
assert json_response(res, 200)["data"]["person"]["participations"] == []
assert res["data"]["person"]["participations"]["elements"] == []
end
test "actor_leave_event/3 should check if the participant is the only creator", %{

View File

@@ -14,7 +14,7 @@ defmodule Mobilizon.GraphQL.Resolvers.PersonTest do
@non_existent_username "nonexistent"
describe "Person Resolver" do
test "get_person/3 returns a person by its username", context do
test "get_person/3 returns a person by its username", %{conn: conn} do
user = insert(:user)
actor = insert(:actor, user: user)
@@ -27,7 +27,8 @@ defmodule Mobilizon.GraphQL.Resolvers.PersonTest do
"""
res =
context.conn
conn
|> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
assert json_response(res, 200)["data"]["person"]["preferredUsername"] ==
@@ -42,7 +43,8 @@ defmodule Mobilizon.GraphQL.Resolvers.PersonTest do
"""
res =
context.conn
conn
|> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
assert json_response(res, 200)["data"]["person"] == nil
@@ -506,7 +508,7 @@ defmodule Mobilizon.GraphQL.Resolvers.PersonTest do
assert_enqueued(
worker: Workers.Background,
args: %{"actor_id" => person_id, "op" => "delete_actor"}
args: %{"actor_id" => person_id, "op" => "delete_actor", "reserve_username" => true}
)
assert %{success: 1, failure: 0} == Oban.drain_queue(:background)
@@ -538,9 +540,11 @@ defmodule Mobilizon.GraphQL.Resolvers.PersonTest do
{
loggedPerson {
participations {
event {
uuid,
title
elements {
event {
uuid,
title
}
}
}
}
@@ -552,7 +556,7 @@ defmodule Mobilizon.GraphQL.Resolvers.PersonTest do
|> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "logged_person"))
assert json_response(res, 200)["data"]["loggedPerson"]["participations"] == []
assert json_response(res, 200)["data"]["loggedPerson"]["participations"]["elements"] == []
event = insert(:event, %{organizer_actor: actor})
insert(:participant, %{actor: actor, event: event})
@@ -562,11 +566,27 @@ defmodule Mobilizon.GraphQL.Resolvers.PersonTest do
|> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "logged_person"))
assert json_response(res, 200)["data"]["loggedPerson"]["participations"] == [
assert json_response(res, 200)["data"]["loggedPerson"]["participations"]["elements"] == [
%{"event" => %{"title" => event.title, "uuid" => event.uuid}}
]
end
@person_participations """
query PersonParticipations($actorId: ID!) {
person(id: $actorId) {
participations {
total,
elements {
event {
uuid,
title
}
}
}
}
}
"""
test "find_person/3 can return the events an identity is going to if it's the same actor",
context do
user = insert(:user)
@@ -574,47 +594,27 @@ defmodule Mobilizon.GraphQL.Resolvers.PersonTest do
insert(:actor, user: user)
actor_from_other_user = insert(:actor)
query = """
{
person(id: "#{actor.id}") {
participations {
event {
uuid,
title
}
}
}
}
"""
res =
context.conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @person_participations,
variables: %{actorId: actor.id}
)
assert res["data"]["person"]["participations"]["elements"] == []
res =
context.conn
|> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
|> AbsintheHelpers.graphql_query(
query: @person_participations,
variables: %{actorId: actor_from_other_user.id}
)
assert json_response(res, 200)["data"]["person"]["participations"] == []
assert res["data"]["person"]["participations"]["elements"] == nil
query = """
{
person(id: "#{actor_from_other_user.id}") {
participations {
event {
uuid,
title
}
}
}
}
"""
res =
context.conn
|> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
assert json_response(res, 200)["data"]["person"]["participations"] == nil
assert hd(json_response(res, 200)["errors"])["message"] ==
assert hd(res["errors"])["message"] ==
"Actor id is not owned by authenticated user"
end
@@ -629,9 +629,11 @@ defmodule Mobilizon.GraphQL.Resolvers.PersonTest do
{
person(id: "#{actor.id}") {
participations(eventId: "#{event.id}") {
event {
uuid,
title
elements {
event {
uuid,
title
}
}
}
}
@@ -643,7 +645,7 @@ defmodule Mobilizon.GraphQL.Resolvers.PersonTest do
|> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
assert json_response(res, 200)["data"]["person"]["participations"] == [
assert json_response(res, 200)["data"]["person"]["participations"]["elements"] == [
%{
"event" => %{
"uuid" => event.uuid,
@@ -653,4 +655,114 @@ defmodule Mobilizon.GraphQL.Resolvers.PersonTest do
]
end
end
describe "suspend_profile/3" do
@suspend_profile_mutation """
mutation SuspendProfile($id: ID!) {
suspendProfile(id: $id) {
id
}
}
"""
@person_query """
query Person($id: ID!) {
person(id: $id) {
id,
suspended
}
}
"""
@moderation_logs_query """
{
actionLogs {
action,
actor {
id,
preferredUsername
},
object {
...on Person {
id,
preferredUsername
}
}
}
}
"""
test "suspends a remote profile", %{conn: conn} do
modo = insert(:user, role: :moderator)
%Actor{id: modo_actor_id} = insert(:actor, user: modo)
%Actor{id: remote_profile_id} = insert(:actor, domain: "mobilizon.org", user: nil)
res =
conn
|> auth_conn(modo)
|> AbsintheHelpers.graphql_query(
query: @suspend_profile_mutation,
variables: %{id: remote_profile_id}
)
assert is_nil(res["errors"])
assert res["data"]["suspendProfile"]["id"] == to_string(remote_profile_id)
assert %{success: 1, failure: 0} == Oban.drain_queue(:background)
res =
conn
|> auth_conn(modo)
|> AbsintheHelpers.graphql_query(
query: @person_query,
variables: %{id: remote_profile_id}
)
assert res["data"]["person"]["suspended"] == true
res =
conn
|> auth_conn(modo)
|> AbsintheHelpers.graphql_query(query: @moderation_logs_query)
actionlog = hd(res["data"]["actionLogs"])
refute is_nil(actionlog)
assert actionlog["action"] == "ACTOR_SUSPENSION"
assert actionlog["actor"]["id"] == to_string(modo_actor_id)
assert actionlog["object"]["id"] == to_string(remote_profile_id)
end
test "doesn't suspend if profile is local", %{conn: conn} do
modo = insert(:user, role: :moderator)
%Actor{} = insert(:actor, user: modo)
%Actor{id: profile_id} = insert(:actor)
res =
conn
|> auth_conn(modo)
|> AbsintheHelpers.graphql_query(
query: @suspend_profile_mutation,
variables: %{id: profile_id}
)
assert hd(res["errors"])["message"] == "No remote profile found with this ID"
end
test "doesn't suspend if user is not at least moderator", %{conn: conn} do
fake_modo = insert(:user)
%Actor{} = insert(:actor, user: fake_modo)
%Actor{id: remote_profile_id} = insert(:actor, domain: "mobilizon.org", user: nil)
res =
conn
|> auth_conn(fake_modo)
|> AbsintheHelpers.graphql_query(
query: @suspend_profile_mutation,
variables: %{id: remote_profile_id}
)
assert hd(res["errors"])["message"] ==
"Only moderators and administrators can suspend a profile"
end
end
end

View File

@@ -57,8 +57,9 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
@valid_single_actor_params %{preferred_username: "test2", keys: "yolo"}
describe "Resolver: Get an user" do
test "find_user/3 returns an user by its id", context do
test "find_user/3 returns an user by its id", %{conn: conn} do
user = insert(:user)
modo = insert(:user, role: :moderator)
query = """
{
@@ -69,7 +70,8 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
"""
res =
context.conn
conn
|> auth_conn(modo)
|> get("/api", AbsintheHelpers.query_skeleton(query, "user"))
assert json_response(res, 200)["data"]["user"]["email"] == user.email
@@ -83,7 +85,8 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
"""
res =
context.conn
conn
|> auth_conn(modo)
|> get("/api", AbsintheHelpers.query_skeleton(query, "user"))
assert json_response(res, 200)["data"]["user"] == nil
@@ -1414,9 +1417,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
assert MapSet.new([actor1.id, actor2.id]) == MapSet.new([actor1_id, actor2_id])
assert_raise Ecto.NoResultsError, fn ->
Users.get_user!(user.id)
end
assert Users.get_user(user.id).disabled == true
assert %{success: 2, failure: 0} == Oban.drain_queue(:background)

View File

@@ -59,7 +59,8 @@ defmodule Mobilizon.ActorsTest do
end
test "list_actors/0 returns all actors", %{actor: %Actor{id: actor_id}} do
assert actor_id == hd(Actors.list_actors()).id
assert %Page{total: 1, elements: [%Actor{id: id}]} = Actors.list_actors()
assert id == actor_id
end
test "get_actor!/1 returns the actor with given id", %{actor: %Actor{id: actor_id} = actor} do
@@ -316,7 +317,7 @@ defmodule Mobilizon.ActorsTest do
assert_enqueued(
worker: Workers.Background,
args: %{"actor_id" => actor.id, "op" => "delete_actor"}
args: %{"actor_id" => actor.id, "op" => "delete_actor", "reserve_username" => true}
)
assert %{success: 1, failure: 0} == Oban.drain_queue(:background)

View File

@@ -4,8 +4,7 @@ defmodule Mobilizon.EventsTest do
import Mobilizon.Factory
alias Mobilizon.Actors.Actor
alias Mobilizon.{Conversations, Events}
alias Mobilizon.Conversations.Comment
alias Mobilizon.Events
alias Mobilizon.Events.{Event, Participant, Session, Tag, TagRelation, Track}
alias Mobilizon.Service.Workers
alias Mobilizon.Storage.Page

View File

@@ -1,6 +1,7 @@
defmodule Mobilizon.UsersTest do
use Mobilizon.DataCase
alias Mobilizon.Storage.Page
alias Mobilizon.Users
alias Mobilizon.Users.{Setting, User}
import Mobilizon.Factory
@@ -13,7 +14,7 @@ defmodule Mobilizon.UsersTest do
test "list_users/0 returns all users" do
user = insert(:user)
users = Users.list_users(nil, nil, :id, :desc)
%Page{elements: users, total: 1} = Users.list_users("", nil, nil, :id, :desc)
assert [user.id] == users |> Enum.map(& &1.id)
end
@@ -52,9 +53,15 @@ defmodule Mobilizon.UsersTest do
assert user = Users.get_user!(user.id)
end
test "delete_user/1 deletes the user" do
test "delete_user/1 empties the user" do
user = insert(:user)
assert {:ok, %User{}} = Users.delete_user(user)
assert Users.get_user(user.id).disabled == true
end
test "delete_user/1 deletes the user" do
user = insert(:user)
assert {:ok, %User{}} = Users.delete_user(user, reserve_email: false)
assert_raise Ecto.NoResultsError, fn -> Users.get_user!(user.id) end
end

View File

@@ -52,6 +52,12 @@ defmodule Mix.Tasks.Mobilizon.UsersTest do
test "delete existing user" do
insert(:user, email: @email)
Delete.run([@email, "-y"])
assert {:ok, %User{disabled: true}} = Users.get_user_by_email(@email)
end
test "full delete existing user" do
insert(:user, email: @email)
Delete.run([@email, "-y", "-f"])
assert {:error, :user_not_found} == Users.get_user_by_email(@email)
end