Add config option to allow anonymous reporting
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
2e64da11e3
commit
dac47d2abb
@ -26,6 +26,7 @@ Also make sure to remove the `EnvironmentFile=` line from the systemd service an
|
|||||||
- Duplicate an event
|
- Duplicate an event
|
||||||
- Ability to handle basic administration settings in the admin panel
|
- Ability to handle basic administration settings in the admin panel
|
||||||
- Added physical address change to the list of important changes that trigger event notifications
|
- Added physical address change to the list of important changes that trigger event notifications
|
||||||
|
- Config option to allow anonymous reporting
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Configuration handling (see above)
|
- Configuration handling (see above)
|
||||||
|
@ -202,6 +202,9 @@ config :mobilizon, :anonymous,
|
|||||||
],
|
],
|
||||||
captcha: [enabled: false]
|
captcha: [enabled: false]
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
reports: [
|
||||||
|
allowed: false
|
||||||
]
|
]
|
||||||
|
|
||||||
config :mobilizon, Oban,
|
config :mobilizon, Oban,
|
||||||
|
@ -92,6 +92,11 @@ config :mobilizon, :instance,
|
|||||||
|
|
||||||
# config :mobilizon, :activitypub, sign_object_fetches: false
|
# config :mobilizon, :activitypub, sign_object_fetches: false
|
||||||
|
|
||||||
|
config :mobilizon, :anonymous,
|
||||||
|
reports: [
|
||||||
|
allowed: true
|
||||||
|
]
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
|
@ -62,7 +62,7 @@ export const COMMENTS_THREADS = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
${COMMENT_RECURSIVE_FRAGMENT}
|
${COMMENT_FIELDS_FRAGMENT}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CREATE_COMMENT_FROM_EVENT = gql`
|
export const CREATE_COMMENT_FROM_EVENT = gql`
|
||||||
|
@ -34,6 +34,9 @@ export const CONFIG = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
reports {
|
||||||
|
allowed
|
||||||
|
}
|
||||||
actorId
|
actorId
|
||||||
}
|
}
|
||||||
location {
|
location {
|
||||||
|
@ -39,6 +39,9 @@ export interface IConfig {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
reports: {
|
||||||
|
allowed: boolean;
|
||||||
|
};
|
||||||
actorId: string;
|
actorId: string;
|
||||||
};
|
};
|
||||||
maps: {
|
maps: {
|
||||||
|
@ -272,7 +272,7 @@
|
|||||||
<b-icon icon="calendar-plus" />
|
<b-icon icon="calendar-plus" />
|
||||||
</span>
|
</span>
|
||||||
</b-dropdown-item>
|
</b-dropdown-item>
|
||||||
<b-dropdown-item aria-role="listitem">
|
<b-dropdown-item aria-role="listitem" v-if="ableToReport">
|
||||||
<span @click="isReportModalActive = true">
|
<span @click="isReportModalActive = true">
|
||||||
{{ $t("Report") }}
|
{{ $t("Report") }}
|
||||||
<b-icon icon="flag" />
|
<b-icon icon="flag" />
|
||||||
@ -750,14 +750,25 @@ export default class Event extends EventMixin {
|
|||||||
|
|
||||||
async reportEvent(content: string, forward: boolean) {
|
async reportEvent(content: string, forward: boolean) {
|
||||||
this.isReportModalActive = false;
|
this.isReportModalActive = false;
|
||||||
|
// @ts-ignore
|
||||||
|
this.$refs.reportModal.close();
|
||||||
if (!this.event.organizerActor) return;
|
if (!this.event.organizerActor) return;
|
||||||
const eventTitle = this.event.title;
|
const eventTitle = this.event.title;
|
||||||
|
let reporterId = null;
|
||||||
|
if (this.currentActor.id) {
|
||||||
|
reporterId = this.currentActor.id;
|
||||||
|
} else {
|
||||||
|
if (this.config.anonymous.reports.allowed) {
|
||||||
|
reporterId = this.config.anonymous.actorId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!reporterId) return;
|
||||||
try {
|
try {
|
||||||
await this.$apollo.mutate<IReport>({
|
await this.$apollo.mutate<IReport>({
|
||||||
mutation: CREATE_REPORT,
|
mutation: CREATE_REPORT,
|
||||||
variables: {
|
variables: {
|
||||||
eventId: this.event.id,
|
eventId: this.event.id,
|
||||||
reporterId: this.currentActor.id,
|
reporterId,
|
||||||
reportedId: this.event.organizerActor.id,
|
reportedId: this.event.organizerActor.id,
|
||||||
content,
|
content,
|
||||||
forward,
|
forward,
|
||||||
@ -996,6 +1007,12 @@ export default class Event extends EventMixin {
|
|||||||
await removeAnonymousParticipation(this.uuid);
|
await removeAnonymousParticipation(this.uuid);
|
||||||
this.anonymousParticipation = null;
|
this.anonymousParticipation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get ableToReport(): boolean {
|
||||||
|
return (
|
||||||
|
this.config && (this.currentActor.id != undefined || this.config.anonymous.reports.allowed)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -154,7 +154,7 @@ import Subtitle from "../components/Utils/Subtitle.vue";
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
update: (data) =>
|
update: (data) =>
|
||||||
data.loggedUser.participations.map(
|
data.loggedUser.participations.elements.map(
|
||||||
(participation: IParticipant) => new Participant(participation)
|
(participation: IParticipant) => new Participant(participation)
|
||||||
),
|
),
|
||||||
skip() {
|
skip() {
|
||||||
|
@ -89,6 +89,9 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
reports: %{
|
||||||
|
allowed: Config.anonymous_reporting?()
|
||||||
|
},
|
||||||
actor_id: Config.anonymous_actor_id()
|
actor_id: Config.anonymous_actor_id()
|
||||||
},
|
},
|
||||||
geocoding: %{
|
geocoding: %{
|
||||||
|
@ -60,9 +60,10 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_event_access(%Event{local: true}), do: true
|
@spec check_event_access(Event.t()) :: boolean()
|
||||||
|
defp check_event_access(%Event{local: true}), do: true
|
||||||
|
|
||||||
def check_event_access(%Event{url: url}) do
|
defp check_event_access(%Event{url: url}) do
|
||||||
relay_actor_id = Config.relay_actor_id()
|
relay_actor_id = Config.relay_actor_id()
|
||||||
Events.check_if_event_has_instance_follow(url, relay_actor_id)
|
Events.check_if_event_has_instance_follow(url, relay_actor_id)
|
||||||
end
|
end
|
||||||
|
@ -7,6 +7,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Report do
|
|||||||
|
|
||||||
alias Mobilizon.Actors
|
alias Mobilizon.Actors
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
|
alias Mobilizon.Config
|
||||||
alias Mobilizon.Reports
|
alias Mobilizon.Reports
|
||||||
alias Mobilizon.Reports.{Note, Report}
|
alias Mobilizon.Reports.{Note, Report}
|
||||||
alias Mobilizon.Users.User
|
alias Mobilizon.Users.User
|
||||||
@ -47,7 +48,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Report do
|
|||||||
def create_report(
|
def create_report(
|
||||||
_parent,
|
_parent,
|
||||||
%{reporter_id: reporter_id} = args,
|
%{reporter_id: reporter_id} = args,
|
||||||
%{context: %{current_user: user}} = _resolution
|
%{context: %{current_user: %User{} = user}} = _resolution
|
||||||
) do
|
) do
|
||||||
with {:is_owned, %Actor{}} <- User.owns_actor(user, reporter_id),
|
with {:is_owned, %Actor{}} <- User.owns_actor(user, reporter_id),
|
||||||
{:ok, _, %Report{} = report} <- API.Reports.report(args) do
|
{:ok, _, %Report{} = report} <- API.Reports.report(args) do
|
||||||
@ -61,6 +62,31 @@ defmodule Mobilizon.GraphQL.Resolvers.Report do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Create a report anonymously if allowed
|
||||||
|
"""
|
||||||
|
def create_report(
|
||||||
|
_parent,
|
||||||
|
%{reporter_id: reporter_id} = args,
|
||||||
|
_resolution
|
||||||
|
) do
|
||||||
|
with {:anonymous_reporting_allowed, true} <-
|
||||||
|
{:anonymous_reporting_allowed, Config.anonymous_reporting?()},
|
||||||
|
{:wrong_id, true} <- {:wrong_id, reporter_id == to_string(Config.anonymous_actor_id())},
|
||||||
|
{:ok, _, %Report{} = report} <- API.Reports.report(args) do
|
||||||
|
{:ok, report}
|
||||||
|
else
|
||||||
|
{:anonymous_reporting_allowed, _} ->
|
||||||
|
{:error, "You need to be logged-in to create reports"}
|
||||||
|
|
||||||
|
{:wrong_id, _} ->
|
||||||
|
{:error, "Reporter ID is not the anonymous actor id"}
|
||||||
|
|
||||||
|
_error ->
|
||||||
|
{:error, "Error while saving report"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def create_report(_parent, _args, _resolution) do
|
def create_report(_parent, _args, _resolution) do
|
||||||
{:error, "You need to be logged-in to create reports"}
|
{:error, "You need to be logged-in to create reports"}
|
||||||
end
|
end
|
||||||
|
@ -59,6 +59,7 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do
|
|||||||
object :anonymous do
|
object :anonymous do
|
||||||
field(:participation, :anonymous_participation)
|
field(:participation, :anonymous_participation)
|
||||||
field(:event_creation, :anonymous_event_creation)
|
field(:event_creation, :anonymous_event_creation)
|
||||||
|
field(:reports, :anonymous_reports)
|
||||||
field(:actor_id, :id)
|
field(:actor_id, :id)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -100,6 +101,10 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do
|
|||||||
field(:enabled, :boolean)
|
field(:enabled, :boolean)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
object :anonymous_reports do
|
||||||
|
field(:allowed, :boolean)
|
||||||
|
end
|
||||||
|
|
||||||
object :resource_provider do
|
object :resource_provider do
|
||||||
field(:type, :string)
|
field(:type, :string)
|
||||||
field(:endpoint, :string)
|
field(:endpoint, :string)
|
||||||
|
@ -139,6 +139,10 @@ defmodule Mobilizon.Config do
|
|||||||
:enabled
|
:enabled
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@spec anonymous_reporting? :: boolean
|
||||||
|
def anonymous_reporting?,
|
||||||
|
do: Application.get_env(:mobilizon, :anonymous)[:reports][:allowed]
|
||||||
|
|
||||||
def instance_resource_providers do
|
def instance_resource_providers do
|
||||||
types = get_in(Application.get_env(:mobilizon, Mobilizon.Service.ResourceProviders), [:types])
|
types = get_in(Application.get_env(:mobilizon, Mobilizon.Service.ResourceProviders), [:types])
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
defmodule Mobilizon.GraphQL.Resolvers.ReportTest do
|
defmodule Mobilizon.GraphQL.Resolvers.ReportTest do
|
||||||
use Mobilizon.Web.ConnCase
|
use Mobilizon.Web.ConnCase
|
||||||
|
use Mobilizon.Tests.Helpers
|
||||||
|
|
||||||
import Mobilizon.Factory
|
import Mobilizon.Factory
|
||||||
|
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
|
alias Mobilizon.Config
|
||||||
alias Mobilizon.Events.Event
|
alias Mobilizon.Events.Event
|
||||||
alias Mobilizon.Reports.{Note, Report}
|
alias Mobilizon.Reports.{Note, Report}
|
||||||
alias Mobilizon.Users.User
|
alias Mobilizon.Users.User
|
||||||
@ -11,19 +13,13 @@ defmodule Mobilizon.GraphQL.Resolvers.ReportTest do
|
|||||||
alias Mobilizon.GraphQL.AbsintheHelpers
|
alias Mobilizon.GraphQL.AbsintheHelpers
|
||||||
|
|
||||||
describe "Resolver: Report a content" do
|
describe "Resolver: Report a content" do
|
||||||
test "create_report/3 creates a report", %{conn: conn} do
|
@create_report_mutation """
|
||||||
%User{} = user_reporter = insert(:user)
|
mutation CreateReport($reporterId: ID!, $reportedId: ID!, $eventId: ID, $content: String) {
|
||||||
%Actor{} = reporter = insert(:actor, user: user_reporter)
|
|
||||||
%Actor{} = reported = insert(:actor)
|
|
||||||
%Event{} = event = insert(:event, organizer_actor: reported)
|
|
||||||
|
|
||||||
mutation = """
|
|
||||||
mutation {
|
|
||||||
createReport(
|
createReport(
|
||||||
reporter_id: #{reporter.id},
|
reporterId: $reporterId,
|
||||||
reported_id: #{reported.id},
|
reportedId: $reportedId,
|
||||||
event_id: #{event.id},
|
eventId: $eventId,
|
||||||
content: "This is an issue"
|
content: $content
|
||||||
) {
|
) {
|
||||||
content,
|
content,
|
||||||
reporter {
|
reporter {
|
||||||
@ -37,41 +33,104 @@ defmodule Mobilizon.GraphQL.Resolvers.ReportTest do
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
clear_config([:anonymous, :reports])
|
||||||
|
|
||||||
|
setup %{conn: conn} do
|
||||||
|
Mobilizon.Config.clear_config_cache()
|
||||||
|
anonymous_actor_id = Config.anonymous_actor_id()
|
||||||
|
{:ok, conn: conn, anonymous_actor_id: anonymous_actor_id}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_report/3 creates a report", %{conn: conn} do
|
||||||
|
%User{} = user_reporter = insert(:user)
|
||||||
|
%Actor{} = reporter = insert(:actor, user: user_reporter)
|
||||||
|
%Actor{} = reported = insert(:actor)
|
||||||
|
%Event{} = event = insert(:event, organizer_actor: reported)
|
||||||
|
|
||||||
res =
|
res =
|
||||||
conn
|
conn
|
||||||
|> auth_conn(user_reporter)
|
|> auth_conn(user_reporter)
|
||||||
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
|
|> AbsintheHelpers.graphql_query(
|
||||||
|
query: @create_report_mutation,
|
||||||
|
variables: %{
|
||||||
|
reportedId: reported.id,
|
||||||
|
reporterId: reporter.id,
|
||||||
|
eventId: event.id,
|
||||||
|
content: "This is an issue"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
assert json_response(res, 200)["errors"] == nil
|
assert res["errors"] == nil
|
||||||
assert json_response(res, 200)["data"]["createReport"]["content"] == "This is an issue"
|
assert res["data"]["createReport"]["content"] == "This is an issue"
|
||||||
assert json_response(res, 200)["data"]["createReport"]["status"] == "OPEN"
|
assert res["data"]["createReport"]["status"] == "OPEN"
|
||||||
assert json_response(res, 200)["data"]["createReport"]["event"]["id"] == to_string(event.id)
|
assert res["data"]["createReport"]["event"]["id"] == to_string(event.id)
|
||||||
|
|
||||||
assert json_response(res, 200)["data"]["createReport"]["reporter"]["id"] ==
|
assert res["data"]["createReport"]["reporter"]["id"] ==
|
||||||
to_string(reporter.id)
|
to_string(reporter.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "create_report/3 without being connected doesn't create any report", %{conn: conn} do
|
test "create_report/3 without being connected doesn't create any report", %{conn: conn} do
|
||||||
%Actor{} = reported = insert(:actor)
|
%Actor{} = reported = insert(:actor)
|
||||||
|
|
||||||
mutation = """
|
res =
|
||||||
mutation {
|
conn
|
||||||
createReport(
|
|> AbsintheHelpers.graphql_query(
|
||||||
reported_id: #{reported.id},
|
query: @create_report_mutation,
|
||||||
reporter_id: 5,
|
variables: %{
|
||||||
|
reportedId: reported.id,
|
||||||
|
reporterId: 5,
|
||||||
content: "This is an issue"
|
content: "This is an issue"
|
||||||
) {
|
|
||||||
content
|
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
"""
|
|
||||||
|
assert res["errors"] |> hd |> Map.get("message") ==
|
||||||
|
"You need to be logged-in to create reports"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_report/3 anonymously creates a report if config has allowed", %{
|
||||||
|
conn: conn,
|
||||||
|
anonymous_actor_id: anonymous_actor_id
|
||||||
|
} do
|
||||||
|
%Actor{} = reported = insert(:actor)
|
||||||
|
Config.put([:anonymous, :reports, :allowed], true)
|
||||||
|
|
||||||
res =
|
res =
|
||||||
conn
|
conn
|
||||||
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
|
|> AbsintheHelpers.graphql_query(
|
||||||
|
query: @create_report_mutation,
|
||||||
|
variables: %{
|
||||||
|
reportedId: reported.id,
|
||||||
|
reporterId: anonymous_actor_id,
|
||||||
|
content: "This is an issue"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
assert json_response(res, 200)["errors"] |> hd |> Map.get("message") ==
|
assert is_nil(res["errors"])
|
||||||
"You need to be logged-in to create reports"
|
assert res["data"]["createReport"]["content"] == "This is an issue"
|
||||||
|
assert res["data"]["createReport"]["status"] == "OPEN"
|
||||||
|
|
||||||
|
assert res["data"]["createReport"]["reporter"]["id"] ==
|
||||||
|
to_string(anonymous_actor_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_report/3 anonymously doesn't creates a report if the anonymous actor ID is wrong",
|
||||||
|
%{conn: conn} do
|
||||||
|
%Actor{} = reported = insert(:actor)
|
||||||
|
Config.put([:anonymous, :reports, :allowed], true)
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> AbsintheHelpers.graphql_query(
|
||||||
|
query: @create_report_mutation,
|
||||||
|
variables: %{
|
||||||
|
reportedId: reported.id,
|
||||||
|
reporterId: 53,
|
||||||
|
content: "This is an issue"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res["errors"] |> hd |> Map.get("message") ==
|
||||||
|
"Reporter ID is not the anonymous actor id"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user