diff --git a/lib/mobilizon/events/comment.ex b/lib/mobilizon/events/comment.ex index d49e459ed..72bca80dd 100644 --- a/lib/mobilizon/events/comment.ex +++ b/lib/mobilizon/events/comment.ex @@ -1,3 +1,13 @@ +import EctoEnum + +defenum(Mobilizon.Events.CommentVisibilityEnum, :comment_visibility_type, [ + :public, + :unlisted, + :private, + :moderated, + :invite +]) + defmodule Mobilizon.Events.Comment do @moduledoc """ An actor comment (for instance on an event or on a group) @@ -14,6 +24,7 @@ defmodule Mobilizon.Events.Comment do field(:text, :string) field(:url, :string) field(:local, :boolean, default: true) + field(:visibility, Mobilizon.Events.CommentVisibilityEnum, default: :public) field(:uuid, Ecto.UUID) belongs_to(:actor, Actor, foreign_key: :actor_id) belongs_to(:attributed_to, Actor, foreign_key: :attributed_to_id) @@ -38,7 +49,7 @@ defmodule Mobilizon.Events.Comment do else: "#{MobilizonWeb.Endpoint.url()}/comments/#{uuid}" comment - |> cast(attrs, [ + |> Ecto.Changeset.cast(attrs, [ :url, :text, :actor_id, diff --git a/lib/mobilizon/events/event.ex b/lib/mobilizon/events/event.ex index 5f76d6e50..c93616e07 100644 --- a/lib/mobilizon/events/event.ex +++ b/lib/mobilizon/events/event.ex @@ -1,5 +1,19 @@ import EctoEnum -defenum(AddressTypeEnum, :address_type, [:physical, :url, :phone, :other]) +defenum(Mobilizon.Events.AddressTypeEnum, :address_type, [:physical, :url, :phone, :other]) + +defenum(Mobilizon.Events.EventVisibilityEnum, :event_visibility_type, [ + :public, + :unlisted, + :private, + :moderated, + :invite +]) + +defenum(Mobilizon.Events.EventStatusEnum, :event_status_type, [ + :tentative, + :confirmed, + :cancelled +]) defmodule Mobilizon.Events.Event do @moduledoc """ @@ -18,17 +32,13 @@ defmodule Mobilizon.Events.Event do field(:description, :string) field(:ends_on, Timex.Ecto.DateTimeWithTimezone) field(:title, :string) - # ??? - field(:state, :integer, default: 0) - # Event status: TENTATIVE 1, CONFIRMED 2, CANCELLED 3 - field(:status, :integer, default: 0) - # If the event is public or private - field(:public, :boolean, default: true) + field(:status, Mobilizon.Events.EventStatusEnum, default: :confirmed) + field(:visibility, Mobilizon.Events.EventVisibilityEnum, default: :public) field(:thumbnail, :string) field(:large_image, :string) field(:publish_at, Timex.Ecto.DateTimeWithTimezone) field(:uuid, Ecto.UUID, default: Ecto.UUID.generate()) - field(:address_type, AddressTypeEnum, default: :physical) + field(:address_type, Mobilizon.Events.AddressTypeEnum, default: :physical) field(:online_address, :string) field(:phone, :string) belongs_to(:organizer_actor, Actor, foreign_key: :organizer_actor_id) @@ -54,9 +64,8 @@ defmodule Mobilizon.Events.Event do :ends_on, :organizer_actor_id, :category_id, - :state, :status, - :public, + :visibility, :thumbnail, :large_image, :publish_at, diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex index 35e24d04e..68c5f1464 100644 --- a/lib/mobilizon/events/events.ex +++ b/lib/mobilizon/events/events.ex @@ -19,11 +19,11 @@ defmodule Mobilizon.Events do queryable end - def get_events_for_actor(%Actor{id: actor_id} = _actor, page \\ nil, limit \\ nil) do + def get_public_events_for_actor(%Actor{id: actor_id} = _actor, page \\ nil, limit \\ nil) do query = from( e in Event, - where: e.organizer_actor_id == ^actor_id, + where: e.organizer_actor_id == ^actor_id and e.visibility in [^:public, ^:unlisted], order_by: [desc: :id], preload: [ :organizer_actor, @@ -50,7 +50,7 @@ defmodule Mobilizon.Events do from( e in Event, select: count(e.id), - where: e.local == ^true + where: e.local == ^true and e.visibility in [^:public, ^:unlisted] ) ) end @@ -60,7 +60,7 @@ defmodule Mobilizon.Events do from( c in Comment, select: count(c.id), - where: c.local == ^true + where: c.local == ^true and c.visibility in [^:public, ^:unlisted] ) ) end @@ -80,7 +80,7 @@ defmodule Mobilizon.Events do e in Event, join: a in Address, on: a.id == e.physical_address_id, - where: st_dwithin_in_meters(^point, a.geom, ^radius), + where: e.visibility == ^:public and st_dwithin_in_meters(^point, a.geom, ^radius), preload: :organizer_actor ) ) @@ -130,17 +130,20 @@ defmodule Mobilizon.Events do """ @spec get_event_full_by_uuid(String.t()) :: Event.t() def get_event_full_by_uuid(uuid) do - event = Repo.get_by(Event, uuid: uuid) - - Repo.preload(event, [ - :organizer_actor, - :category, - :sessions, - :tracks, - :tags, - :participants, - :physical_address - ]) + from( + e in Event, + where: e.uuid == ^uuid and e.visibility in [^:public, ^:unlisted], + preload: [ + :organizer_actor, + :category, + :sessions, + :tracks, + :tags, + :participants, + :physical_address + ] + ) + |> Repo.one() end @doc """ @@ -166,7 +169,7 @@ defmodule Mobilizon.Events do def get_event_full_by_url(url) do case Repo.one( from(e in Event, - where: e.url == ^url, + where: e.url == ^url and e.visibility in [^:public, ^:unlisted], preload: [ :organizer_actor, :category, @@ -187,17 +190,20 @@ defmodule Mobilizon.Events do Gets an event by it's URL """ def get_event_full_by_url!(url) do - event = Repo.get_by!(Event, url: url) - - Repo.preload(event, [ - :organizer_actor, - :category, - :sessions, - :tracks, - :tags, - :participants, - :physical_address - ]) + Repo.one( + from(e in Event, + where: e.url == ^url and e.visibility in [^:public, ^:unlisted], + preload: [ + :organizer_actor, + :category, + :sessions, + :tracks, + :tags, + :participants, + :physical_address + ] + ) + ) end @doc """ @@ -211,7 +217,11 @@ defmodule Mobilizon.Events do """ def list_events(page \\ nil, limit \\ nil) do query = - from(e in Event, preload: [:organizer_actor]) + from( + e in Event, + where: e.visibility == ^:public, + preload: [:organizer_actor] + ) |> paginate(page, limit) Repo.all(query) @@ -228,7 +238,7 @@ defmodule Mobilizon.Events do query = from(e in Event, - where: ilike(e.title, ^like_sanitize(name)), + where: e.visibility == ^:public and ilike(e.title, ^like_sanitize(name)), preload: [:organizer_actor] ) |> paginate(page, limit) @@ -860,7 +870,7 @@ defmodule Mobilizon.Events do alias Mobilizon.Events.Comment @doc """ - Returns the list of comments. + Returns the list of public comments. ## Examples @@ -869,14 +879,14 @@ defmodule Mobilizon.Events do """ def list_comments do - Repo.all(Comment) + Repo.all(from(c in Comment, where: c.visibility == ^:public)) end - def get_comments_for_actor(%Actor{id: actor_id}, page \\ nil, limit \\ nil) do + def get_public_comments_for_actor(%Actor{id: actor_id}, page \\ nil, limit \\ nil) do query = from( c in Comment, - where: c.actor_id == ^actor_id, + where: c.actor_id == ^actor_id and c.visibility in [^:public, ^:unlisted], order_by: [desc: :id], preload: [ :actor, diff --git a/lib/mobilizon_web/controllers/activity_pub_controller.ex b/lib/mobilizon_web/controllers/activity_pub_controller.ex index 0777f8514..c7c6a9636 100644 --- a/lib/mobilizon_web/controllers/activity_pub_controller.ex +++ b/lib/mobilizon_web/controllers/activity_pub_controller.ex @@ -47,7 +47,7 @@ defmodule MobilizonWeb.ActivityPubController do def event(conn, %{"uuid" => uuid}) do with %Event{} = event <- Events.get_event_full_by_uuid(uuid), - true <- event.public do + true <- event.visibility in [:public, :unlisted] do conn |> put_resp_header("content-type", "application/activity+json") |> json(ObjectView.render("event.json", %{event: event |> Utils.make_event_data()})) diff --git a/lib/service/activity_pub/activity_pub.ex b/lib/service/activity_pub/activity_pub.ex index 1fc8fbcb3..13979a32f 100644 --- a/lib/service/activity_pub/activity_pub.ex +++ b/lib/service/activity_pub/activity_pub.ex @@ -474,8 +474,8 @@ defmodule Mobilizon.Service.ActivityPub do def fetch_public_activities_for_actor(%Actor{} = actor, page, limit) do case actor.type do :Person -> - {:ok, events, total_events} = Events.get_events_for_actor(actor, page, limit) - {:ok, comments, total_comments} = Events.get_comments_for_actor(actor, page, limit) + {:ok, events, total_events} = Events.get_public_events_for_actor(actor, page, limit) + {:ok, comments, total_comments} = Events.get_public_comments_for_actor(actor, page, limit) event_activities = Enum.map(events, &event_to_activity/1) diff --git a/priv/repo/migrations/20180702150922_add_address_type.exs b/priv/repo/migrations/20180702150922_add_address_type.exs index d89f75097..d9085e08d 100644 --- a/priv/repo/migrations/20180702150922_add_address_type.exs +++ b/priv/repo/migrations/20180702150922_add_address_type.exs @@ -2,7 +2,7 @@ defmodule Mobilizon.Repo.Migrations.AddAddressType do use Ecto.Migration def up do - AddressTypeEnum.create_type + Mobilizon.Events.AddressTypeEnum.create_type alter table(:events) do add :address_type, :address_type add :online_address, :string @@ -21,7 +21,7 @@ defmodule Mobilizon.Repo.Migrations.AddAddressType do remove :online_address remove :phone end - AddressTypeEnum.drop_type + Mobilizon.Events.AddressTypeEnum.drop_type drop constraint(:events, "events_physical_address_id_fkey") rename table(:events), :physical_address_id, to: :address_id alter table(:events) do diff --git a/priv/repo/migrations/20190103150805_fix_event_visibility.exs b/priv/repo/migrations/20190103150805_fix_event_visibility.exs new file mode 100644 index 000000000..b08dfba06 --- /dev/null +++ b/priv/repo/migrations/20190103150805_fix_event_visibility.exs @@ -0,0 +1,36 @@ +defmodule Mobilizon.Repo.Migrations.FixEventVisibility do + use Ecto.Migration + + def up do + Mobilizon.Events.EventVisibilityEnum.create_type + Mobilizon.Events.EventStatusEnum.create_type + Mobilizon.Events.CommentVisibilityEnum.create_type + alter table(:events) do + remove(:public) + remove(:status) + remove(:state) + add(:visibility, Mobilizon.Events.EventVisibilityEnum.type()) + add(:status, Mobilizon.Events.EventStatusEnum.type()) + end + + alter table(:comments) do + add(:visibility, Mobilizon.Events.CommentVisibilityEnum.type()) + end + end + + def down do + alter table(:events) do + remove(:visibility) + remove(:status) + add(:state, :integer, null: false, default: 0) + add(:public, :boolean, null: false, default: false) + add(:status, :integer, null: false, default: 0) + end + alter table(:comments) do + remove(:visibility) + end + Mobilizon.Events.EventVisibilityEnum.drop_type + Mobilizon.Events.EventStatusEnum.drop_type + Mobilizon.Events.CommentVisibilityEnum.drop_type + end +end diff --git a/test/mobilizon/events/events_test.exs b/test/mobilizon/events/events_test.exs index 8103f0e45..d16e56e50 100644 --- a/test/mobilizon/events/events_test.exs +++ b/test/mobilizon/events/events_test.exs @@ -125,15 +125,15 @@ defmodule Mobilizon.EventsTest do assert %Ecto.Changeset{} = Events.change_event(event) end - test "get_events_for_actor/1", %{actor: actor, event: event} do - assert {:ok, [event_found], 1} = Events.get_events_for_actor(actor) + test "get_public_events_for_actor/1", %{actor: actor, event: event} do + assert {:ok, [event_found], 1} = Events.get_public_events_for_actor(actor) assert event_found.title == event.title end - test "get_events_for_actor/3", %{actor: actor, event: event} do + test "get_public_events_for_actor/3", %{actor: actor, event: event} do event1 = insert(:event, organizer_actor: actor) - with {:ok, events_found, 2} <- Events.get_events_for_actor(actor, 1, 10) do + with {:ok, events_found, 2} <- Events.get_public_events_for_actor(actor, 1, 10) do event_ids = MapSet.new(events_found |> Enum.map(& &1.id)) assert event_ids == MapSet.new([event.id, event1.id]) else @@ -142,10 +142,11 @@ defmodule Mobilizon.EventsTest do end end - test "get_events_for_actor/3 with limited results", %{actor: actor, event: event} do + test "get_public_events_for_actor/3 with limited results", %{actor: actor, event: event} do event1 = insert(:event, organizer_actor: actor) - with {:ok, [%Event{id: event_found_id}], 2} <- Events.get_events_for_actor(actor, 1, 1) do + with {:ok, [%Event{id: event_found_id}], 2} <- + Events.get_public_events_for_actor(actor, 1, 1) do assert event_found_id in [event.id, event1.id] else err -> diff --git a/test/mobilizon_web/controllers/activity_pub_controller_test.exs b/test/mobilizon_web/controllers/activity_pub_controller_test.exs index 4038a0432..3dfa42d95 100644 --- a/test/mobilizon_web/controllers/activity_pub_controller_test.exs +++ b/test/mobilizon_web/controllers/activity_pub_controller_test.exs @@ -42,7 +42,7 @@ defmodule MobilizonWeb.ActivityPubControllerTest do end test "it returns 404 for non-public events", %{conn: conn} do - event = insert(:event, public: false) + event = insert(:event, visibility: :private) conn = conn diff --git a/test/mobilizon_web/resolvers/event_resolver_test.exs b/test/mobilizon_web/resolvers/event_resolver_test.exs index 5af5f12e9..e82a1e10b 100644 --- a/test/mobilizon_web/resolvers/event_resolver_test.exs +++ b/test/mobilizon_web/resolvers/event_resolver_test.exs @@ -241,5 +241,63 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do assert json_response(res, 200)["data"]["events"] |> length == 0 end + + test "list_events/3 doesn't list private events", context do + insert(:event, visibility: :private) + insert(:event, visibility: :unlisted) + insert(:event, visibility: :moderated) + insert(:event, visibility: :invite) + + query = """ + { + events { + uuid, + } + } + """ + + res = + context.conn + |> get("/api", AbsintheHelpers.query_skeleton(query, "event")) + + assert json_response(res, 200)["data"]["events"] |> Enum.map(& &1["uuid"]) == [] + end + + test "find_event/3 returns an unlisted event", context do + event = insert(:event, visibility: :unlisted) + + query = """ + { + event(uuid: "#{event.uuid}") { + uuid, + } + } + """ + + res = + context.conn + |> get("/api", AbsintheHelpers.query_skeleton(query, "event")) + + assert json_response(res, 200)["data"]["event"]["uuid"] == to_string(event.uuid) + end + + test "find_event/3 doesn't return a private event", context do + event = insert(:event, visibility: :private) + + query = """ + { + event(uuid: "#{event.uuid}") { + uuid, + } + } + """ + + res = + context.conn + |> get("/api", AbsintheHelpers.query_skeleton(query, "event")) + + assert json_response(res, 200)["errors"] |> hd |> Map.get("message") == + "Event with UUID #{event.uuid} not found" + end end end diff --git a/test/support/factory.ex b/test/support/factory.ex index 321b43d7f..3e52914ac 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -105,7 +105,7 @@ defmodule Mobilizon.Factory do organizer_actor: actor, category: build(:category), physical_address: build(:address), - public: true, + visibility: :public, url: "@#{actor.url}/#{Ecto.UUID.generate()}" } end