Add admin dashboard, event reporting, moderation report screens, moderation log

Close #156 and #158

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2019-09-09 09:31:08 +02:00
parent 164429964a
commit 27f2597b07
77 changed files with 1682 additions and 201 deletions

View File

@@ -15,6 +15,7 @@ defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
alias Mobilizon.Service.HTTPSignatures.Signature
alias Mobilizon.Service.ActivityPub
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
import Mock
setup_all do
HTTPoison.start()
@@ -111,7 +112,6 @@ defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
end
describe "deletion" do
# TODO: The delete activity it relayed and fetched once again (and then not found /o\)
test "it creates a delete activity and deletes the original event" do
event = insert(:event)
event = Events.get_event_full_by_url!(event.url)
@@ -124,6 +124,25 @@ defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
assert Events.get_event_by_url(event.url) == nil
end
test "it deletes the original event but only locally if needed" do
with_mock ActivityPub.Utils,
maybe_federate: fn _ -> :ok end,
lazy_put_activity_defaults: fn args -> args end do
event = insert(:event)
event = Events.get_event_full_by_url!(event.url)
{:ok, delete, _} = ActivityPub.delete(event, false)
assert delete.data["type"] == "Delete"
assert delete.data["actor"] == event.organizer_actor.url
assert delete.data["object"] == event.url
assert delete.local == false
assert Events.get_event_by_url(event.url) == nil
assert_called(ActivityPub.Utils.maybe_federate(delete))
end
end
test "it creates a delete activity and deletes the original comment" do
comment = insert(:comment)
comment = Events.get_comment_full_from_url!(comment.url)

View File

@@ -22,7 +22,7 @@ defmodule Mobilizon.Service.Admin.ActionLogServiceTest do
%ActionLog{
target_type: "Elixir.Mobilizon.Reports.Report",
target_id: report_id,
action: "update",
action: :update,
actor: moderator
}} = log_action(moderator, "update", report)
end
@@ -35,7 +35,7 @@ defmodule Mobilizon.Service.Admin.ActionLogServiceTest do
%ActionLog{
target_type: "Elixir.Mobilizon.Reports.Note",
target_id: note_id,
action: "create",
action: :create,
actor: moderator
}} = log_action(moderator, "create", report)
end

View File

@@ -25,7 +25,7 @@ defmodule MobilizonWeb.API.ReportTest do
Reports.report(%{
reporter_actor_id: reporter_id,
reported_actor_id: reported_id,
report_content: comment,
content: comment,
event_id: event_id,
comments_ids: []
})
@@ -58,7 +58,7 @@ defmodule MobilizonWeb.API.ReportTest do
Reports.report(%{
reporter_actor_id: reporter_id,
reported_actor_id: reported_id,
report_content: comment,
content: comment,
event_id: nil,
comments_ids: [comment_1_id, comment_2_id]
})
@@ -92,7 +92,7 @@ defmodule MobilizonWeb.API.ReportTest do
Reports.report(%{
reporter_actor_id: reporter_id,
reported_actor_id: reported_id,
report_content: comment,
content: comment,
event_id: nil,
comments_ids: [comment_1_id, comment_2_id],
forward: true
@@ -121,7 +121,7 @@ defmodule MobilizonWeb.API.ReportTest do
Reports.report(%{
reporter_actor_id: reporter_id,
reported_actor_id: reported_id,
report_content: "This is not a nice thing",
content: "This is not a nice thing",
event_id: nil,
comments_ids: [comment_1_id],
forward: true
@@ -147,7 +147,7 @@ defmodule MobilizonWeb.API.ReportTest do
Reports.report(%{
reporter_actor_id: reporter_id,
reported_actor_id: reported_id,
report_content: "This is not a nice thing",
content: "This is not a nice thing",
event_id: nil,
comments_ids: [comment_1_id],
forward: true

View File

@@ -31,8 +31,9 @@ defmodule MobilizonWeb.NodeInfoControllerTest do
end
test "Get node info", %{conn: conn} do
# We clear the cache because it might have been initialized by other tests
Cachex.clear(:statistics)
conn = get(conn, node_info_path(conn, :nodeinfo, "2.1"))
resp = json_response(conn, 200)
assert resp == %{
@@ -44,7 +45,7 @@ defmodule MobilizonWeb.NodeInfoControllerTest do
"protocols" => ["activitypub"],
"services" => %{"inbound" => [], "outbound" => ["atom1.0"]},
"software" => %{
"name" => "mobilizon",
"name" => "Mobilizon",
"version" => Keyword.get(@instance, :version),
"repository" => Keyword.get(@instance, :repository)
},

View File

@@ -3,6 +3,7 @@ defmodule MobilizonWeb.Resolvers.AdminResolverTest do
use MobilizonWeb.ConnCase
import Mobilizon.Factory
alias Mobilizon.Events.Event
alias Mobilizon.Actors.Actor
alias Mobilizon.Users.User
alias Mobilizon.Reports.{Report, Note}
@@ -62,21 +63,60 @@ defmodule MobilizonWeb.Resolvers.AdminResolverTest do
assert json_response(res, 200)["data"]["actionLogs"] == [
%{
"action" => "report_update_resolved",
"action" => "NOTE_DELETION",
"actor" => %{"preferredUsername" => moderator_2.preferred_username},
"object" => %{"content" => @note_content}
},
%{
"action" => "NOTE_CREATION",
"actor" => %{"preferredUsername" => moderator_2.preferred_username},
"object" => %{"content" => @note_content}
},
%{
"action" => "REPORT_UPDATE_RESOLVED",
"actor" => %{"preferredUsername" => moderator.preferred_username},
"object" => %{"id" => to_string(report.id), "status" => "RESOLVED"}
},
%{
"action" => "note_creation",
"actor" => %{"preferredUsername" => moderator_2.preferred_username},
"object" => %{"content" => @note_content}
},
%{
"action" => "note_deletion",
"actor" => %{"preferredUsername" => moderator_2.preferred_username},
"object" => %{"content" => @note_content}
}
]
end
end
describe "Resolver: Get the dashboard statistics" do
test "get_dashboard/3 gets dashboard information", %{conn: conn} do
%Event{title: title} = insert(:event)
%User{} = user_admin = insert(:user, role: :administrator)
query = """
{
dashboard {
lastPublicEventPublished {
title
}
numberOfUsers,
numberOfComments,
numberOfEvents,
numberOfReports
}
}
"""
res =
conn
|> get("/api", AbsintheHelpers.query_skeleton(query, "actionLogs"))
assert json_response(res, 200)["errors"] |> hd |> Map.get("message") ==
"You need to be logged-in and an administrator to access dashboard statistics"
res =
conn
|> auth_conn(user_admin)
|> get("/api", AbsintheHelpers.query_skeleton(query, "actionLogs"))
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["dashboard"]["lastPublicEventPublished"]["title"] ==
title
end
end
end

View File

@@ -731,7 +731,7 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["deleteEvent"]["id"] == event.id
assert json_response(res, 200)["data"]["deleteEvent"]["id"] == to_string(event.id)
res =
conn
@@ -815,6 +815,72 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
assert hd(json_response(res, 200)["errors"])["message"] =~ "cannot delete"
end
test "delete_event/3 allows a event being deleted by a moderator and creates a entry in actionLogs",
%{
conn: conn,
user: _user,
actor: _actor
} do
user_moderator = insert(:user, role: :moderator)
actor_moderator = insert(:actor, user: user_moderator)
actor2 = insert(:actor)
event = insert(:event, organizer_actor: actor2)
mutation = """
mutation {
deleteEvent(
actor_id: #{actor_moderator.id},
event_id: #{event.id}
) {
id
}
}
"""
res =
conn
|> auth_conn(user_moderator)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert json_response(res, 200)["data"]["deleteEvent"]["id"] == to_string(event.id)
query = """
{
actionLogs {
action,
actor {
preferredUsername
},
object {
... on Report {
id,
status
},
... on ReportNote {
content
}
... on Event {
id,
title
}
}
}
}
"""
res =
conn
|> auth_conn(user_moderator)
|> get("/api", AbsintheHelpers.query_skeleton(query, "actionLogs"))
assert hd(json_response(res, 200)["data"]["actionLogs"]) == %{
"action" => "EVENT_DELETION",
"actor" => %{"preferredUsername" => actor_moderator.preferred_username},
"object" => %{"title" => event.title, "id" => to_string(event.id)}
}
end
test "list_related_events/3 should give related events", %{
conn: conn,
actor: actor

View File

@@ -43,7 +43,8 @@ defmodule MobilizonWeb.Resolvers.FeedTokenResolverTest do
assert json_response(res, 200)["data"]["createFeedToken"]["user"]["id"] ==
to_string(user.id)
assert json_response(res, 200)["data"]["createFeedToken"]["actor"]["id"] == actor2.id
assert json_response(res, 200)["data"]["createFeedToken"]["actor"]["id"] ==
to_string(actor2.id)
# The token is present for the user
query = """
@@ -209,8 +210,12 @@ defmodule MobilizonWeb.Resolvers.FeedTokenResolverTest do
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["deleteFeedToken"]["user"]["id"] == user.id
assert json_response(res, 200)["data"]["deleteFeedToken"]["actor"]["id"] == actor.id
assert json_response(res, 200)["data"]["deleteFeedToken"]["user"]["id"] ==
to_string(user.id)
assert json_response(res, 200)["data"]["deleteFeedToken"]["actor"]["id"] ==
to_string(actor.id)
query = """
{

View File

@@ -163,7 +163,7 @@ defmodule MobilizonWeb.Resolvers.GroupResolverTest do
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["deleteGroup"]["id"] == group.id
assert json_response(res, 200)["data"]["deleteGroup"]["id"] == to_string(group.id)
res =
conn

View File

@@ -40,8 +40,8 @@ defmodule MobilizonWeb.Resolvers.MemberResolverTest do
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["joinGroup"]["role"] == "not_approved"
assert json_response(res, 200)["data"]["joinGroup"]["parent"]["id"] == group.id
assert json_response(res, 200)["data"]["joinGroup"]["actor"]["id"] == actor.id
assert json_response(res, 200)["data"]["joinGroup"]["parent"]["id"] == to_string(group.id)
assert json_response(res, 200)["data"]["joinGroup"]["actor"]["id"] == to_string(actor.id)
mutation = """
mutation {
@@ -167,8 +167,8 @@ defmodule MobilizonWeb.Resolvers.MemberResolverTest do
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["leaveGroup"]["parent"]["id"] == group.id
assert json_response(res, 200)["data"]["leaveGroup"]["actor"]["id"] == actor.id
assert json_response(res, 200)["data"]["leaveGroup"]["parent"]["id"] == to_string(group.id)
assert json_response(res, 200)["data"]["leaveGroup"]["actor"]["id"] == to_string(actor.id)
end
test "leave_group/3 should check if the member is the only administrator", %{

View File

@@ -50,8 +50,8 @@ defmodule MobilizonWeb.Resolvers.ParticipantResolverTest do
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["joinEvent"]["role"] == "participant"
assert json_response(res, 200)["data"]["joinEvent"]["event"]["id"] == event.id
assert json_response(res, 200)["data"]["joinEvent"]["actor"]["id"] == actor.id
assert json_response(res, 200)["data"]["joinEvent"]["event"]["id"] == to_string(event.id)
assert json_response(res, 200)["data"]["joinEvent"]["actor"]["id"] == to_string(actor.id)
mutation = """
mutation {
@@ -119,7 +119,7 @@ defmodule MobilizonWeb.Resolvers.ParticipantResolverTest do
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert hd(json_response(res, 200)["errors"])["message"] ==
"Event with this ID 1042 doesn't exist"
"Event with this ID \"1042\" doesn't exist"
end
test "actor_leave_event/3 should delete a participant from an event", %{
@@ -153,8 +153,10 @@ defmodule MobilizonWeb.Resolvers.ParticipantResolverTest do
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["leaveEvent"]["event"]["id"] == event.id
assert json_response(res, 200)["data"]["leaveEvent"]["actor"]["id"] == participant.actor.id
assert json_response(res, 200)["data"]["leaveEvent"]["event"]["id"] == to_string(event.id)
assert json_response(res, 200)["data"]["leaveEvent"]["actor"]["id"] ==
to_string(participant.actor.id)
query = """
{

View File

@@ -21,7 +21,7 @@ defmodule MobilizonWeb.Resolvers.ReportResolverTest do
reporter_actor_id: #{reporter.id},
reported_actor_id: #{reported.id},
event_id: #{event.id},
report_content: "This is an issue"
content: "This is an issue"
) {
content,
reporter {
@@ -43,8 +43,10 @@ defmodule MobilizonWeb.Resolvers.ReportResolverTest do
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["createReport"]["content"] == "This is an issue"
assert json_response(res, 200)["data"]["createReport"]["status"] == "OPEN"
assert json_response(res, 200)["data"]["createReport"]["event"]["id"] == event.id
assert json_response(res, 200)["data"]["createReport"]["reporter"]["id"] == reporter.id
assert json_response(res, 200)["data"]["createReport"]["event"]["id"] == to_string(event.id)
assert json_response(res, 200)["data"]["createReport"]["reporter"]["id"] ==
to_string(reporter.id)
end
test "create_report/3 without being connected doesn't create any report", %{conn: conn} do
@@ -55,7 +57,7 @@ defmodule MobilizonWeb.Resolvers.ReportResolverTest do
createReport(
reported_actor_id: #{reported.id},
reporter_actor_id: 5,
report_content: "This is an issue"
content: "This is an issue"
) {
content
}
@@ -109,7 +111,7 @@ defmodule MobilizonWeb.Resolvers.ReportResolverTest do
assert json_response(res, 200)["data"]["updateReportStatus"]["status"] == "RESOLVED"
assert json_response(res, 200)["data"]["updateReportStatus"]["reporter"]["id"] ==
report.reporter.id
to_string(report.reporter.id)
end
test "create_report/3 without being connected doesn't create any report", %{conn: conn} do
@@ -172,9 +174,14 @@ defmodule MobilizonWeb.Resolvers.ReportResolverTest do
test "get a list of reports", %{conn: conn} do
%User{} = user_moderator = insert(:user, role: :moderator)
%Report{id: report_1_id} = insert(:report)
%Report{id: report_2_id} = insert(:report)
%Report{id: report_3_id} = insert(:report)
# Report don't hold millisecond information so we need to wait a bit
# between each insert to keep order
%Report{id: report_1_id} = insert(:report, content: "My content 1")
Process.sleep(1000)
%Report{id: report_2_id} = insert(:report, content: "My content 2")
Process.sleep(1000)
%Report{id: report_3_id} = insert(:report, content: "My content 3")
%Report{} = insert(:report, status: :closed)
query = """
{
@@ -182,7 +189,9 @@ defmodule MobilizonWeb.Resolvers.ReportResolverTest do
id,
reported {
preferredUsername
}
},
content,
updatedAt
}
}
"""
@@ -196,7 +205,7 @@ defmodule MobilizonWeb.Resolvers.ReportResolverTest do
assert json_response(res, 200)["data"]["reports"]
|> Enum.map(fn report -> Map.get(report, "id") end) ==
Enum.map([report_1_id, report_2_id, report_3_id], &to_string/1)
Enum.map([report_3_id, report_2_id, report_1_id], &to_string/1)
query = """
{
@@ -360,7 +369,9 @@ defmodule MobilizonWeb.Resolvers.ReportResolverTest do
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["deleteReportNote"]["id"] == report_note_id
assert json_response(res, 200)["data"]["deleteReportNote"]["id"] ==
to_string(report_note_id)
end
end
end