From b0bc8dfa5ddab2531a4012264134239628e012bc Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 14 Jan 2019 17:13:17 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=82=EF=B8=8F=20=20Split=20GraphQL=20s?= =?UTF-8?q?chema=20into=20several=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Citharel --- lib/mobilizon_web/schema.ex | 296 +----------------- lib/mobilizon_web/schema/actor.ex | 62 ++++ lib/mobilizon_web/schema/actors/follower.ex | 15 + lib/mobilizon_web/schema/actors/group.ex | 68 ++++ lib/mobilizon_web/schema/actors/member.ex | 13 + lib/mobilizon_web/schema/actors/person.ex | 44 +++ lib/mobilizon_web/schema/address.ex | 36 +++ lib/mobilizon_web/schema/comment.ex | 14 + lib/mobilizon_web/schema/custom/point.ex | 38 +++ lib/mobilizon_web/schema/event.ex | 49 +++ lib/mobilizon_web/schema/events/category.ex | 11 + .../schema/events/participant.ex | 14 + lib/mobilizon_web/schema/user.ex | 33 ++ 13 files changed, 403 insertions(+), 290 deletions(-) create mode 100644 lib/mobilizon_web/schema/actor.ex create mode 100644 lib/mobilizon_web/schema/actors/follower.ex create mode 100644 lib/mobilizon_web/schema/actors/group.ex create mode 100644 lib/mobilizon_web/schema/actors/member.ex create mode 100644 lib/mobilizon_web/schema/actors/person.ex create mode 100644 lib/mobilizon_web/schema/address.ex create mode 100644 lib/mobilizon_web/schema/comment.ex create mode 100644 lib/mobilizon_web/schema/custom/point.ex create mode 100644 lib/mobilizon_web/schema/event.ex create mode 100644 lib/mobilizon_web/schema/events/category.ex create mode 100644 lib/mobilizon_web/schema/events/participant.ex create mode 100644 lib/mobilizon_web/schema/user.ex diff --git a/lib/mobilizon_web/schema.ex b/lib/mobilizon_web/schema.ex index 02e7543a8..f9d2021ca 100644 --- a/lib/mobilizon_web/schema.ex +++ b/lib/mobilizon_web/schema.ex @@ -10,285 +10,23 @@ defmodule MobilizonWeb.Schema do alias Mobilizon.Events.{Event, Comment, Participant} import_types(MobilizonWeb.Schema.Custom.UUID) + import_types(MobilizonWeb.Schema.Custom.Point) import_types(Absinthe.Type.Custom) import_types(Absinthe.Plug.Types) + import_types(MobilizonWeb.Schema.ActorInterface) + import_types(MobilizonWeb.Schema.Actors.PersonType) + import_types(MobilizonWeb.Schema.Actors.GroupType) + import_types(MobilizonWeb.Schema.CommentType) + alias MobilizonWeb.Resolvers - @desc """ - Represents a person identity - """ - object :person do - interfaces([:actor]) - field(:user, :user, description: "The user this actor is associated to") - - field(:member_of, list_of(:member), description: "The list of groups this person is member of") - - field(:url, :string, description: "The ActivityPub actor's URL") - field(:type, :actor_type, description: "The type of Actor (Person, Group,…)") - field(:name, :string, description: "The actor's displayed name") - field(:domain, :string, description: "The actor's domain if (null if it's this instance)") - field(:local, :boolean, description: "If the actor is from this instance") - field(:summary, :string, description: "The actor's summary") - field(:preferred_username, :string, description: "The actor's preferred username") - field(:keys, :string, description: "The actors RSA Keys") - - field(:manually_approves_followers, :boolean, - description: "Whether the actors manually approves followers" - ) - - field(:suspended, :boolean, description: "If the actor is suspended") - field(:avatar_url, :string, description: "The actor's avatar url") - field(:banner_url, :string, description: "The actor's banner url") - - # These one should have a privacy setting - field(:following, list_of(:follower), description: "List of followings") - field(:followers, list_of(:follower), description: "List of followers") - field(:followersCount, :integer, description: "Number of followers for this actor") - field(:followingCount, :integer, description: "Number of actors following this actor") - - # This one should have a privacy setting - field(:organized_events, list_of(:event), - resolve: dataloader(Events), - description: "A list of the events this actor has organized" - ) - end - - @desc """ - Represents a group of actors - """ - object :group do - interfaces([:actor]) - - field(:url, :string, description: "The ActivityPub actor's URL") - field(:type, :actor_type, description: "The type of Actor (Person, Group,…)") - field(:name, :string, description: "The actor's displayed name") - field(:domain, :string, description: "The actor's domain if (null if it's this instance)") - field(:local, :boolean, description: "If the actor is from this instance") - field(:summary, :string, description: "The actor's summary") - field(:preferred_username, :string, description: "The actor's preferred username") - field(:keys, :string, description: "The actors RSA Keys") - - field(:manually_approves_followers, :boolean, - description: "Whether the actors manually approves followers" - ) - - field(:suspended, :boolean, description: "If the actor is suspended") - field(:avatar_url, :string, description: "The actor's avatar url") - field(:banner_url, :string, description: "The actor's banner url") - - # These one should have a privacy setting - field(:following, list_of(:follower), description: "List of followings") - field(:followers, list_of(:follower), description: "List of followers") - field(:followersCount, :integer, description: "Number of followers for this actor") - field(:followingCount, :integer, description: "Number of actors following this actor") - - # This one should have a privacy setting - field(:organized_events, list_of(:event), - resolve: dataloader(Events), - description: "A list of the events this actor has organized" - ) - - field(:types, :group_type, description: "The type of group : Group, Community,…") - - field(:openness, :openness, - description: "Whether the group is opened to all or has restricted access" - ) - - field(:members, non_null(list_of(:member)), description: "List of group members") - end - - @desc """ - Describes how an actor is opened to follows - """ - enum :openness do - value(:invite_only, description: "The actor can only be followed by invitation") - - value(:moderated, description: "The actor needs to accept the following before it's effective") - - value(:open, description: "The actor is open to followings") - end - - @desc """ - The types of Group that exist - """ - enum :group_type do - value(:group, description: "A private group of persons") - value(:community, description: "A public group of many actors") - end - - @desc "An ActivityPub actor" - interface :actor do - field(:url, :string, description: "The ActivityPub actor's URL") - field(:type, :actor_type, description: "The type of Actor (Person, Group,…)") - field(:name, :string, description: "The actor's displayed name") - field(:domain, :string, description: "The actor's domain if (null if it's this instance)") - field(:local, :boolean, description: "If the actor is from this instance") - field(:summary, :string, description: "The actor's summary") - field(:preferred_username, :string, description: "The actor's preferred username") - field(:keys, :string, description: "The actors RSA Keys") - - field(:manually_approves_followers, :boolean, - description: "Whether the actors manually approves followers" - ) - - field(:suspended, :boolean, description: "If the actor is suspended") - field(:avatar_url, :string, description: "The actor's avatar url") - field(:banner_url, :string, description: "The actor's banner url") - - # These one should have a privacy setting - field(:following, list_of(:follower), description: "List of followings") - field(:followers, list_of(:follower), description: "List of followers") - field(:followersCount, :integer, description: "Number of followers for this actor") - field(:followingCount, :integer, description: "Number of actors following this actor") - - # This one should have a privacy setting - field(:organized_events, list_of(:event), - resolve: dataloader(Events), - description: "A list of the events this actor has organized" - ) - - # This one is for the person itself **only** - # field(:feed, list_of(:event), description: "List of events the actor sees in his or her feed") - - # field(:memberships, list_of(:member)) - - resolve_type(fn - %Actor{type: :Person}, _ -> - :person - - %Actor{type: :Group}, _ -> - :group - end) - end - - @desc "The list of types an actor can be" - enum :actor_type do - value(:Person, description: "An ActivityPub Person") - value(:Application, description: "An ActivityPub Application") - value(:Group, description: "An ActivityPub Group") - value(:Organization, description: "An ActivityPub Organization") - value(:Service, description: "An ActivityPub Service") - end - - @desc "A local user of Mobilizon" - object :user do - field(:id, non_null(:id), description: "The user's ID") - field(:email, non_null(:string), description: "The user's email") - - field(:profiles, non_null(list_of(:person)), - description: "The user's list of profiles (identities)" - ) - - field(:default_actor, non_null(:person), description: "The user's default actor") - - field(:confirmed_at, :datetime, - description: "The datetime when the user was confirmed/activated" - ) - - field(:confirmation_sent_at, :datetime, - description: "The datetime the last activation/confirmation token was sent" - ) - - field(:confirmation_token, :string, description: "The account activation/confirmation token") - - field(:reset_password_sent_at, :datetime, - description: "The datetime last reset password email was sent" - ) - - field(:reset_password_token, :string, - description: "The token sent when requesting password token" - ) - end - @desc "A JWT and the associated user ID" object :login do field(:token, non_null(:string), description: "A JWT Token for this session") field(:user, non_null(:user), description: "The user associated to this session") end - @desc "An event" - object :event do - field(:uuid, :uuid, description: "The Event UUID") - field(:url, :string, description: "The ActivityPub Event URL") - field(:local, :boolean, description: "Whether the event is local or not") - field(:title, :string, description: "The event's title") - field(:description, :string, description: "The event's description") - field(:begins_on, :datetime, description: "Datetime for when the event begins") - field(:ends_on, :datetime, description: "Datetime for when the event ends") - field(:state, :integer, description: "State of the event") - field(:status, :integer, description: "Status of the event") - field(:public, :boolean, description: "Whether the event is public or not") - # TODO replace me with picture object - field(:thumbnail, :string, description: "A thumbnail picture for the event") - # TODO replace me with banner - field(:large_image, :string, description: "A large picture for the event") - field(:publish_at, :datetime, description: "When the event was published") - field(:address_type, :address_type, description: "The type of the event's address") - # TODO implement these properly with an interface - # field(:online_address, :string, description: "???") - # field(:phone, :string, description: "") - - field(:organizer_actor, :person, - resolve: dataloader(Actors), - description: "The event's organizer (as a person)" - ) - - field(:attributed_to, :actor, description: "Who the event is attributed to (often a group)") - # field(:tags, list_of(:tag)) - field(:category, :category, description: "The event's category") - - field(:participants, list_of(:participant), - resolve: &Resolvers.Event.list_participants_for_event/3, - description: "The event's participants" - ) - - # field(:tracks, list_of(:track)) - # field(:sessions, list_of(:session)) - # field(:physical_address, :address) - - field(:updated_at, :datetime, description: "When the event was last updated") - field(:created_at, :datetime, description: "When the event was created") - end - - @desc "A comment" - object :comment do - field(:uuid, :uuid) - field(:url, :string) - field(:local, :boolean) - field(:text, :string) - field(:primaryLanguage, :string) - field(:replies, list_of(:comment)) - field(:threadLanguages, non_null(list_of(:string))) - end - - @desc "Represents a participant to an event" - object :participant do - field(:event, :event, - resolve: dataloader(Events), - description: "The event which the actor participates in" - ) - - field(:actor, :actor, description: "The actor that participates to the event") - field(:role, :integer, description: "The role of this actor at this event") - end - - @desc "The list of types an address can be" - enum :address_type do - value(:physical, description: "The address is physical, like a postal address") - value(:url, description: "The address is on the Web, like an URL") - value(:phone, description: "The address is a phone number for a conference") - value(:other, description: "The address is something else") - end - - @desc "A category" - object :category do - field(:id, :id, description: "The category's ID") - field(:description, :string, description: "The category's description") - field(:picture, :picture, description: "The category's picture") - field(:title, :string, description: "The category's title") - end - @desc "A picture" object :picture do field(:url, :string, description: "The URL for this picture") @@ -314,28 +52,6 @@ defmodule MobilizonWeb.Schema do field(:published, :datetime, description: "Datetime when the notification was published") end - @desc """ - Represents a member of a group - """ - object :member do - field(:parent, :group, description: "Of which the profile is member") - field(:person, :person, description: "Which profile is member of") - field(:role, :integer, description: "The role of this membership") - field(:approved, :boolean, description: "Whether this membership has been approved") - end - - @desc """ - Represents an actor's follower - """ - object :follower do - field(:target_actor, :actor, description: "What or who the profile follows") - field(:actor, :actor, description: "Which profile follows") - - field(:approved, :boolean, - description: "Whether the follow has been approved by the target actor" - ) - end - union :object do types([:event, :person, :group, :comment, :follower, :member, :participant]) diff --git a/lib/mobilizon_web/schema/actor.ex b/lib/mobilizon_web/schema/actor.ex new file mode 100644 index 000000000..d93ac5041 --- /dev/null +++ b/lib/mobilizon_web/schema/actor.ex @@ -0,0 +1,62 @@ +defmodule MobilizonWeb.Schema.ActorInterface do + use Absinthe.Schema.Notation + import Absinthe.Resolution.Helpers, only: [dataloader: 1] + alias Mobilizon.Actors.Actor + + import_types(MobilizonWeb.Schema.Actors.FollowerType) + import_types(MobilizonWeb.Schema.EventType) + + @desc "An ActivityPub actor" + interface :actor do + field(:url, :string, description: "The ActivityPub actor's URL") + field(:type, :actor_type, description: "The type of Actor (Person, Group,…)") + field(:name, :string, description: "The actor's displayed name") + field(:domain, :string, description: "The actor's domain if (null if it's this instance)") + field(:local, :boolean, description: "If the actor is from this instance") + field(:summary, :string, description: "The actor's summary") + field(:preferred_username, :string, description: "The actor's preferred username") + field(:keys, :string, description: "The actors RSA Keys") + + field(:manually_approves_followers, :boolean, + description: "Whether the actors manually approves followers" + ) + + field(:suspended, :boolean, description: "If the actor is suspended") + field(:avatar_url, :string, description: "The actor's avatar url") + field(:banner_url, :string, description: "The actor's banner url") + + # These one should have a privacy setting + field(:following, list_of(:follower), description: "List of followings") + field(:followers, list_of(:follower), description: "List of followers") + field(:followersCount, :integer, description: "Number of followers for this actor") + field(:followingCount, :integer, description: "Number of actors following this actor") + + # This one should have a privacy setting + field(:organized_events, list_of(:event), + resolve: dataloader(Events), + description: "A list of the events this actor has organized" + ) + + # This one is for the person itself **only** + # field(:feed, list_of(:event), description: "List of events the actor sees in his or her feed") + + # field(:memberships, list_of(:member)) + + resolve_type(fn + %Actor{type: :Person}, _ -> + :person + + %Actor{type: :Group}, _ -> + :group + end) + end + + @desc "The list of types an actor can be" + enum :actor_type do + value(:Person, description: "An ActivityPub Person") + value(:Application, description: "An ActivityPub Application") + value(:Group, description: "An ActivityPub Group") + value(:Organization, description: "An ActivityPub Organization") + value(:Service, description: "An ActivityPub Service") + end +end diff --git a/lib/mobilizon_web/schema/actors/follower.ex b/lib/mobilizon_web/schema/actors/follower.ex new file mode 100644 index 000000000..163deef79 --- /dev/null +++ b/lib/mobilizon_web/schema/actors/follower.ex @@ -0,0 +1,15 @@ +defmodule MobilizonWeb.Schema.Actors.FollowerType do + use Absinthe.Schema.Notation + + @desc """ + Represents an actor's follower + """ + object :follower do + field(:target_actor, :actor, description: "What or who the profile follows") + field(:actor, :actor, description: "Which profile follows") + + field(:approved, :boolean, + description: "Whether the follow has been approved by the target actor" + ) + end +end diff --git a/lib/mobilizon_web/schema/actors/group.ex b/lib/mobilizon_web/schema/actors/group.ex new file mode 100644 index 000000000..60a248ef6 --- /dev/null +++ b/lib/mobilizon_web/schema/actors/group.ex @@ -0,0 +1,68 @@ +defmodule MobilizonWeb.Schema.Actors.GroupType do + use Absinthe.Schema.Notation + import Absinthe.Resolution.Helpers, only: [dataloader: 1] + import_types(MobilizonWeb.Schema.Actors.MemberType) + + @desc """ + Represents a group of actors + """ + object :group do + interfaces([:actor]) + + field(:url, :string, description: "The ActivityPub actor's URL") + field(:type, :actor_type, description: "The type of Actor (Person, Group,…)") + field(:name, :string, description: "The actor's displayed name") + field(:domain, :string, description: "The actor's domain if (null if it's this instance)") + field(:local, :boolean, description: "If the actor is from this instance") + field(:summary, :string, description: "The actor's summary") + field(:preferred_username, :string, description: "The actor's preferred username") + field(:keys, :string, description: "The actors RSA Keys") + + field(:manually_approves_followers, :boolean, + description: "Whether the actors manually approves followers" + ) + + field(:suspended, :boolean, description: "If the actor is suspended") + field(:avatar_url, :string, description: "The actor's avatar url") + field(:banner_url, :string, description: "The actor's banner url") + + # These one should have a privacy setting + field(:following, list_of(:follower), description: "List of followings") + field(:followers, list_of(:follower), description: "List of followers") + field(:followersCount, :integer, description: "Number of followers for this actor") + field(:followingCount, :integer, description: "Number of actors following this actor") + + # This one should have a privacy setting + field(:organized_events, list_of(:event), + resolve: dataloader(Events), + description: "A list of the events this actor has organized" + ) + + field(:types, :group_type, description: "The type of group : Group, Community,…") + + field(:openness, :openness, + description: "Whether the group is opened to all or has restricted access" + ) + + field(:members, non_null(list_of(:member)), description: "List of group members") + end + + @desc """ + The types of Group that exist + """ + enum :group_type do + value(:group, description: "A private group of persons") + value(:community, description: "A public group of many actors") + end + + @desc """ + Describes how an actor is opened to follows + """ + enum :openness do + value(:invite_only, description: "The actor can only be followed by invitation") + + value(:moderated, description: "The actor needs to accept the following before it's effective") + + value(:open, description: "The actor is open to followings") + end +end diff --git a/lib/mobilizon_web/schema/actors/member.ex b/lib/mobilizon_web/schema/actors/member.ex new file mode 100644 index 000000000..97aef0491 --- /dev/null +++ b/lib/mobilizon_web/schema/actors/member.ex @@ -0,0 +1,13 @@ +defmodule MobilizonWeb.Schema.Actors.MemberType do + use Absinthe.Schema.Notation + + @desc """ + Represents a member of a group + """ + object :member do + field(:parent, :group, description: "Of which the profile is member") + field(:person, :person, description: "Which profile is member of") + field(:role, :integer, description: "The role of this membership") + field(:approved, :boolean, description: "Whether this membership has been approved") + end +end diff --git a/lib/mobilizon_web/schema/actors/person.ex b/lib/mobilizon_web/schema/actors/person.ex new file mode 100644 index 000000000..2ddb39120 --- /dev/null +++ b/lib/mobilizon_web/schema/actors/person.ex @@ -0,0 +1,44 @@ +defmodule MobilizonWeb.Schema.Actors.PersonType do + use Absinthe.Schema.Notation + import Absinthe.Resolution.Helpers, only: [dataloader: 1] + import_types(MobilizonWeb.Schema.UserType) + + @desc """ + Represents a person identity + """ + object :person do + interfaces([:actor]) + field(:user, :user, description: "The user this actor is associated to") + + field(:member_of, list_of(:member), description: "The list of groups this person is member of") + + field(:url, :string, description: "The ActivityPub actor's URL") + field(:type, :actor_type, description: "The type of Actor (Person, Group,…)") + field(:name, :string, description: "The actor's displayed name") + field(:domain, :string, description: "The actor's domain if (null if it's this instance)") + field(:local, :boolean, description: "If the actor is from this instance") + field(:summary, :string, description: "The actor's summary") + field(:preferred_username, :string, description: "The actor's preferred username") + field(:keys, :string, description: "The actors RSA Keys") + + field(:manually_approves_followers, :boolean, + description: "Whether the actors manually approves followers" + ) + + field(:suspended, :boolean, description: "If the actor is suspended") + field(:avatar_url, :string, description: "The actor's avatar url") + field(:banner_url, :string, description: "The actor's banner url") + + # These one should have a privacy setting + field(:following, list_of(:follower), description: "List of followings") + field(:followers, list_of(:follower), description: "List of followers") + field(:followersCount, :integer, description: "Number of followers for this actor") + field(:followingCount, :integer, description: "Number of actors following this actor") + + # This one should have a privacy setting + field(:organized_events, list_of(:event), + resolve: dataloader(Events), + description: "A list of the events this actor has organized" + ) + end +end diff --git a/lib/mobilizon_web/schema/address.ex b/lib/mobilizon_web/schema/address.ex new file mode 100644 index 000000000..476575a7e --- /dev/null +++ b/lib/mobilizon_web/schema/address.ex @@ -0,0 +1,36 @@ +defmodule MobilizonWeb.Schema.AddressType do + use Absinthe.Schema.Notation + + object :physical_address do + field(:type, :address_type) + field(:geom, :point) + field(:floor, :string) + field(:streetAddress, :string) + field(:addressLocality, :string) + field(:postalCode, :string) + field(:addressRegion, :string) + field(:addressCountry, :string) + field(:description, :string) + field(:name, :string) + end + + object :phone_address do + field(:type, :address_type) + field(:phone, :string) + field(:info, :string) + end + + object :online_address do + field(:type, :address_type) + field(:url, :string) + field(:info, :string) + end + + @desc "The list of types an address can be" + enum :address_type do + value(:physical, description: "The address is physical, like a postal address") + value(:url, description: "The address is on the Web, like an URL") + value(:phone, description: "The address is a phone number for a conference") + value(:other, description: "The address is something else") + end +end diff --git a/lib/mobilizon_web/schema/comment.ex b/lib/mobilizon_web/schema/comment.ex new file mode 100644 index 000000000..3ac004702 --- /dev/null +++ b/lib/mobilizon_web/schema/comment.ex @@ -0,0 +1,14 @@ +defmodule MobilizonWeb.Schema.CommentType do + use Absinthe.Schema.Notation + + @desc "A comment" + object :comment do + field(:uuid, :uuid) + field(:url, :string) + field(:local, :boolean) + field(:text, :string) + field(:primaryLanguage, :string) + field(:replies, list_of(:comment)) + field(:threadLanguages, non_null(list_of(:string))) + end +end diff --git a/lib/mobilizon_web/schema/custom/point.ex b/lib/mobilizon_web/schema/custom/point.ex new file mode 100644 index 000000000..7bd3cf974 --- /dev/null +++ b/lib/mobilizon_web/schema/custom/point.ex @@ -0,0 +1,38 @@ +defmodule MobilizonWeb.Schema.Custom.Point do + @moduledoc """ + The geom scalar type allows Geo.PostGIS.Geometry strings to be passed in and out. + Requires `{:geo, "~> 3.0"},` package: https://github.com/elixir-ecto/ecto + """ + use Absinthe.Schema.Notation + + scalar :point, name: "Point" do + description(""" + The `Point` scalar type represents Point geographic information compliant string data, + represented as floats separated by a semi-colon. The geodetic system is WGS 84 + """) + + serialize(&encode/1) + parse(&decode/1) + end + + @spec decode(Absinthe.Blueprint.Input.String.t()) :: {:ok, term()} | :error + @spec decode(Absinthe.Blueprint.Input.Null.t()) :: {:ok, nil} + defp decode(%Absinthe.Blueprint.Input.String{value: value}) do + with [_, _] = lonlat <- String.split(value, ";", trim: true), + [{lon, ""}, {lat, ""}] <- Enum.map(lonlat, &Float.parse(&1)) do + {:ok, %Geo.Point{coordinates: {lon, lat}, srid: 4326}} + else + _ -> :error + end + end + + defp decode(%Absinthe.Blueprint.Input.Null{}) do + {:ok, nil} + end + + defp decode(_) do + :error + end + + defp encode(%Geo.Point{coordinates: {lon, lat}, srid: 4326}), do: "#{lon};#{lat}" +end diff --git a/lib/mobilizon_web/schema/event.ex b/lib/mobilizon_web/schema/event.ex new file mode 100644 index 000000000..0ed60c52f --- /dev/null +++ b/lib/mobilizon_web/schema/event.ex @@ -0,0 +1,49 @@ +defmodule MobilizonWeb.Schema.EventType do + use Absinthe.Schema.Notation + import Absinthe.Resolution.Helpers, only: [dataloader: 1] + import_types(MobilizonWeb.Schema.AddressType) + import_types(MobilizonWeb.Schema.Events.ParticipantType) + import_types(MobilizonWeb.Schema.Events.CategoryType) + + @desc "An event" + object :event do + field(:uuid, :uuid, description: "The Event UUID") + field(:url, :string, description: "The ActivityPub Event URL") + field(:local, :boolean, description: "Whether the event is local or not") + field(:title, :string, description: "The event's title") + field(:description, :string, description: "The event's description") + field(:begins_on, :datetime, description: "Datetime for when the event begins") + field(:ends_on, :datetime, description: "Datetime for when the event ends") + field(:state, :integer, description: "State of the event") + field(:status, :integer, description: "Status of the event") + field(:public, :boolean, description: "Whether the event is public or not") + # TODO replace me with picture object + field(:thumbnail, :string, description: "A thumbnail picture for the event") + # TODO replace me with banner + field(:large_image, :string, description: "A large picture for the event") + field(:publish_at, :datetime, description: "When the event was published") + field(:physical_address, :physical_address, description: "The type of the event's address") + field(:online_address, :online_address, description: "Online address of the event") + field(:phone_address, :phone_address, description: "Phone address for the event") + + field(:organizer_actor, :person, + resolve: dataloader(Actors), + description: "The event's organizer (as a person)" + ) + + field(:attributed_to, :actor, description: "Who the event is attributed to (often a group)") + # field(:tags, list_of(:tag)) + field(:category, :category, description: "The event's category") + + field(:participants, list_of(:participant), + resolve: &Resolvers.Event.list_participants_for_event/3, + description: "The event's participants" + ) + + # field(:tracks, list_of(:track)) + # field(:sessions, list_of(:session)) + + field(:updated_at, :datetime, description: "When the event was last updated") + field(:created_at, :datetime, description: "When the event was created") + end +end diff --git a/lib/mobilizon_web/schema/events/category.ex b/lib/mobilizon_web/schema/events/category.ex new file mode 100644 index 000000000..24f31edb7 --- /dev/null +++ b/lib/mobilizon_web/schema/events/category.ex @@ -0,0 +1,11 @@ +defmodule MobilizonWeb.Schema.Events.CategoryType do + use Absinthe.Schema.Notation + + @desc "A category" + object :category do + field(:id, :id, description: "The category's ID") + field(:description, :string, description: "The category's description") + field(:picture, :picture, description: "The category's picture") + field(:title, :string, description: "The category's title") + end +end diff --git a/lib/mobilizon_web/schema/events/participant.ex b/lib/mobilizon_web/schema/events/participant.ex new file mode 100644 index 000000000..54df1f753 --- /dev/null +++ b/lib/mobilizon_web/schema/events/participant.ex @@ -0,0 +1,14 @@ +defmodule MobilizonWeb.Schema.Events.ParticipantType do + use Absinthe.Schema.Notation + + @desc "Represents a participant to an event" + object :participant do + field(:event, :event, + resolve: dataloader(Events), + description: "The event which the actor participates in" + ) + + field(:actor, :actor, description: "The actor that participates to the event") + field(:role, :integer, description: "The role of this actor at this event") + end +end diff --git a/lib/mobilizon_web/schema/user.ex b/lib/mobilizon_web/schema/user.ex new file mode 100644 index 000000000..d908c4e7e --- /dev/null +++ b/lib/mobilizon_web/schema/user.ex @@ -0,0 +1,33 @@ +defmodule MobilizonWeb.Schema.UserType do + use Absinthe.Schema.Notation + + @desc "A local user of Mobilizon" + object :user do + field(:id, non_null(:id), description: "The user's ID") + field(:email, non_null(:string), description: "The user's email") + + field(:profiles, non_null(list_of(:person)), + description: "The user's list of profiles (identities)" + ) + + field(:default_actor, non_null(:person), description: "The user's default actor") + + field(:confirmed_at, :datetime, + description: "The datetime when the user was confirmed/activated" + ) + + field(:confirmation_sent_at, :datetime, + description: "The datetime the last activation/confirmation token was sent" + ) + + field(:confirmation_token, :string, description: "The account activation/confirmation token") + + field(:reset_password_sent_at, :datetime, + description: "The datetime last reset password email was sent" + ) + + field(:reset_password_token, :string, + description: "The token sent when requesting password token" + ) + end +end From 289ba0396095033fe4951cde41650c96628fe1ab Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 14 Jan 2019 17:48:08 +0100 Subject: [PATCH 2/3] Remove address_type and rename phone to phone_address An event can indeed have several address types Signed-off-by: Thomas Citharel --- js/src/components/Event/Event.vue | 4 +-- js/src/graphql/event.ts | 10 +++---- lib/mobilizon/events/event.ex | 10 ++----- lib/mobilizon_web/schema.ex | 4 +-- lib/mobilizon_web/schema/actor.ex | 3 ++ lib/mobilizon_web/schema/actors/follower.ex | 3 ++ lib/mobilizon_web/schema/actors/group.ex | 3 ++ lib/mobilizon_web/schema/actors/member.ex | 3 ++ lib/mobilizon_web/schema/actors/person.ex | 3 ++ lib/mobilizon_web/schema/address.ex | 3 ++ lib/mobilizon_web/schema/comment.ex | 17 +++++++++++ lib/mobilizon_web/schema/event.ex | 30 ++++++++++++++++--- lib/mobilizon_web/schema/events/category.ex | 3 ++ .../schema/events/participant.ex | 4 +++ lib/mobilizon_web/schema/user.ex | 3 ++ .../20190114162055_remove_address_type.exs | 11 +++++++ .../resolvers/event_resolver_test.exs | 3 +- 17 files changed, 93 insertions(+), 24 deletions(-) create mode 100644 priv/repo/migrations/20190114162055_remove_address_type.exs diff --git a/js/src/components/Event/Event.vue b/js/src/components/Event/Event.vue index 6fa6c9e7b..a7f443823 100644 --- a/js/src/components/Event/Event.vue +++ b/js/src/components/Event/Event.vue @@ -105,9 +105,9 @@ - + {{ event.physical_address.streetAddress }} - + Mobile diff --git a/js/src/graphql/event.ts b/js/src/graphql/event.ts index 444669892..14906976f 100644 --- a/js/src/graphql/event.ts +++ b/js/src/graphql/event.ts @@ -12,13 +12,12 @@ export const FETCH_EVENT = gql` ends_on, state, status, - public, + visibility, thumbnail, large_image, publish_at, - # address_type, # online_address, - # phone, + # phone_address, organizerActor { avatarUrl, preferredUsername, @@ -56,13 +55,12 @@ export const FETCH_EVENTS = gql` ends_on, state, status, - public, + visibility, thumbnail, large_image, publish_at, - # address_type, # online_address, - # phone, + # phone_address, organizerActor { avatarUrl, preferredUsername, diff --git a/lib/mobilizon/events/event.ex b/lib/mobilizon/events/event.ex index c93616e07..6f36bcc45 100644 --- a/lib/mobilizon/events/event.ex +++ b/lib/mobilizon/events/event.ex @@ -1,5 +1,4 @@ import EctoEnum -defenum(Mobilizon.Events.AddressTypeEnum, :address_type, [:physical, :url, :phone, :other]) defenum(Mobilizon.Events.EventVisibilityEnum, :event_visibility_type, [ :public, @@ -38,9 +37,8 @@ defmodule Mobilizon.Events.Event do field(:large_image, :string) field(:publish_at, Timex.Ecto.DateTimeWithTimezone) field(:uuid, Ecto.UUID, default: Ecto.UUID.generate()) - field(:address_type, Mobilizon.Events.AddressTypeEnum, default: :physical) field(:online_address, :string) - field(:phone, :string) + field(:phone_address, :string) belongs_to(:organizer_actor, Actor, foreign_key: :organizer_actor_id) belongs_to(:attributed_to, Actor, foreign_key: :attributed_to_id) many_to_many(:tags, Tag, join_through: "events_tags") @@ -69,9 +67,8 @@ defmodule Mobilizon.Events.Event do :thumbnail, :large_image, :publish_at, - :address_type, :online_address, - :phone + :phone_address ]) |> cast_assoc(:tags) |> cast_assoc(:physical_address) @@ -82,8 +79,7 @@ defmodule Mobilizon.Events.Event do :organizer_actor_id, :category_id, :url, - :uuid, - :address_type + :uuid ]) end diff --git a/lib/mobilizon_web/schema.ex b/lib/mobilizon_web/schema.ex index f9d2021ca..afdac3809 100644 --- a/lib/mobilizon_web/schema.ex +++ b/lib/mobilizon_web/schema.ex @@ -4,7 +4,6 @@ defmodule MobilizonWeb.Schema do """ use Absinthe.Schema - import Absinthe.Resolution.Helpers, only: [dataloader: 1] alias Mobilizon.{Actors, Events} alias Mobilizon.Actors.{Actor, Follower, Member} alias Mobilizon.Events.{Event, Comment, Participant} @@ -200,9 +199,8 @@ defmodule MobilizonWeb.Schema do arg(:thumbnail, :string) arg(:large_image, :string) arg(:publish_at, :datetime) - arg(:address_type, non_null(:address_type)) arg(:online_address, :string) - arg(:phone, :string) + arg(:phone_address, :string) arg(:organizer_actor_username, non_null(:string)) arg(:category, non_null(:string)) diff --git a/lib/mobilizon_web/schema/actor.ex b/lib/mobilizon_web/schema/actor.ex index d93ac5041..c3a051094 100644 --- a/lib/mobilizon_web/schema/actor.ex +++ b/lib/mobilizon_web/schema/actor.ex @@ -1,4 +1,7 @@ defmodule MobilizonWeb.Schema.ActorInterface do + @moduledoc """ + Schema representation for Actor + """ use Absinthe.Schema.Notation import Absinthe.Resolution.Helpers, only: [dataloader: 1] alias Mobilizon.Actors.Actor diff --git a/lib/mobilizon_web/schema/actors/follower.ex b/lib/mobilizon_web/schema/actors/follower.ex index 163deef79..50f3cb3ae 100644 --- a/lib/mobilizon_web/schema/actors/follower.ex +++ b/lib/mobilizon_web/schema/actors/follower.ex @@ -1,4 +1,7 @@ defmodule MobilizonWeb.Schema.Actors.FollowerType do + @moduledoc """ + Schema representation for Follower + """ use Absinthe.Schema.Notation @desc """ diff --git a/lib/mobilizon_web/schema/actors/group.ex b/lib/mobilizon_web/schema/actors/group.ex index 60a248ef6..1dab34591 100644 --- a/lib/mobilizon_web/schema/actors/group.ex +++ b/lib/mobilizon_web/schema/actors/group.ex @@ -1,4 +1,7 @@ defmodule MobilizonWeb.Schema.Actors.GroupType do + @moduledoc """ + Schema representation for Group + """ use Absinthe.Schema.Notation import Absinthe.Resolution.Helpers, only: [dataloader: 1] import_types(MobilizonWeb.Schema.Actors.MemberType) diff --git a/lib/mobilizon_web/schema/actors/member.ex b/lib/mobilizon_web/schema/actors/member.ex index 97aef0491..26848f914 100644 --- a/lib/mobilizon_web/schema/actors/member.ex +++ b/lib/mobilizon_web/schema/actors/member.ex @@ -1,4 +1,7 @@ defmodule MobilizonWeb.Schema.Actors.MemberType do + @moduledoc """ + Schema representation for Member + """ use Absinthe.Schema.Notation @desc """ diff --git a/lib/mobilizon_web/schema/actors/person.ex b/lib/mobilizon_web/schema/actors/person.ex index 2ddb39120..46b11dece 100644 --- a/lib/mobilizon_web/schema/actors/person.ex +++ b/lib/mobilizon_web/schema/actors/person.ex @@ -1,4 +1,7 @@ defmodule MobilizonWeb.Schema.Actors.PersonType do + @moduledoc """ + Schema representation for Person + """ use Absinthe.Schema.Notation import Absinthe.Resolution.Helpers, only: [dataloader: 1] import_types(MobilizonWeb.Schema.UserType) diff --git a/lib/mobilizon_web/schema/address.ex b/lib/mobilizon_web/schema/address.ex index 476575a7e..d3b560a16 100644 --- a/lib/mobilizon_web/schema/address.ex +++ b/lib/mobilizon_web/schema/address.ex @@ -1,4 +1,7 @@ defmodule MobilizonWeb.Schema.AddressType do + @moduledoc """ + Schema representation for Address + """ use Absinthe.Schema.Notation object :physical_address do diff --git a/lib/mobilizon_web/schema/comment.ex b/lib/mobilizon_web/schema/comment.ex index 3ac004702..0768ad06e 100644 --- a/lib/mobilizon_web/schema/comment.ex +++ b/lib/mobilizon_web/schema/comment.ex @@ -1,4 +1,7 @@ defmodule MobilizonWeb.Schema.CommentType do + @moduledoc """ + Schema representation for Comment + """ use Absinthe.Schema.Notation @desc "A comment" @@ -6,9 +9,23 @@ defmodule MobilizonWeb.Schema.CommentType do field(:uuid, :uuid) field(:url, :string) field(:local, :boolean) + field(:visibility, :comment_visibility) field(:text, :string) field(:primaryLanguage, :string) field(:replies, list_of(:comment)) field(:threadLanguages, non_null(list_of(:string))) end + + @desc "The list of visibility options for a comment" + enum :comment_visibility do + value(:public, description: "Publically listed and federated. Can be shared.") + value(:unlisted, description: "Visible only to people with the link - or invited") + + value(:private, + description: "Visible only to people members of the group or followers of the person" + ) + + value(:moderated, description: "Visible only after a moderator accepted") + value(:invite, description: "visible only to people invited") + end end diff --git a/lib/mobilizon_web/schema/event.ex b/lib/mobilizon_web/schema/event.ex index 0ed60c52f..2ff2192c3 100644 --- a/lib/mobilizon_web/schema/event.ex +++ b/lib/mobilizon_web/schema/event.ex @@ -1,4 +1,7 @@ defmodule MobilizonWeb.Schema.EventType do + @moduledoc """ + Schema representation for Event + """ use Absinthe.Schema.Notation import Absinthe.Resolution.Helpers, only: [dataloader: 1] import_types(MobilizonWeb.Schema.AddressType) @@ -14,9 +17,8 @@ defmodule MobilizonWeb.Schema.EventType do field(:description, :string, description: "The event's description") field(:begins_on, :datetime, description: "Datetime for when the event begins") field(:ends_on, :datetime, description: "Datetime for when the event ends") - field(:state, :integer, description: "State of the event") - field(:status, :integer, description: "Status of the event") - field(:public, :boolean, description: "Whether the event is public or not") + field(:status, :event_status, description: "Status of the event") + field(:visibility, :event_visibility, description: "The event's visibility") # TODO replace me with picture object field(:thumbnail, :string, description: "A thumbnail picture for the event") # TODO replace me with banner @@ -36,7 +38,7 @@ defmodule MobilizonWeb.Schema.EventType do field(:category, :category, description: "The event's category") field(:participants, list_of(:participant), - resolve: &Resolvers.Event.list_participants_for_event/3, + resolve: &MobilizonWeb.Resolvers.Event.list_participants_for_event/3, description: "The event's participants" ) @@ -46,4 +48,24 @@ defmodule MobilizonWeb.Schema.EventType do field(:updated_at, :datetime, description: "When the event was last updated") field(:created_at, :datetime, description: "When the event was created") end + + @desc "The list of visibility options for an event" + enum :event_visibility do + value(:public, description: "Publically listed and federated. Can be shared.") + value(:unlisted, description: "Visible only to people with the link - or invited") + + value(:private, + description: "Visible only to people members of the group or followers of the person" + ) + + value(:moderated, description: "Visible only after a moderator accepted") + value(:invite, description: "visible only to people invited") + end + + @desc "The list of possible options for the event's status" + enum :event_status do + value(:tentative, description: "The event is tentative") + value(:confirmed, description: "The event is confirmed") + value(:cancelled, description: "The event is cancelled") + end end diff --git a/lib/mobilizon_web/schema/events/category.ex b/lib/mobilizon_web/schema/events/category.ex index 24f31edb7..25e263fe6 100644 --- a/lib/mobilizon_web/schema/events/category.ex +++ b/lib/mobilizon_web/schema/events/category.ex @@ -1,4 +1,7 @@ defmodule MobilizonWeb.Schema.Events.CategoryType do + @moduledoc """ + Schema representation for Category + """ use Absinthe.Schema.Notation @desc "A category" diff --git a/lib/mobilizon_web/schema/events/participant.ex b/lib/mobilizon_web/schema/events/participant.ex index 54df1f753..47a6b36b9 100644 --- a/lib/mobilizon_web/schema/events/participant.ex +++ b/lib/mobilizon_web/schema/events/participant.ex @@ -1,5 +1,9 @@ defmodule MobilizonWeb.Schema.Events.ParticipantType do + @moduledoc """ + Schema representation for Participant + """ use Absinthe.Schema.Notation + import Absinthe.Resolution.Helpers, only: [dataloader: 1] @desc "Represents a participant to an event" object :participant do diff --git a/lib/mobilizon_web/schema/user.ex b/lib/mobilizon_web/schema/user.ex index d908c4e7e..b1106de93 100644 --- a/lib/mobilizon_web/schema/user.ex +++ b/lib/mobilizon_web/schema/user.ex @@ -1,4 +1,7 @@ defmodule MobilizonWeb.Schema.UserType do + @moduledoc """ + Schema representation for User + """ use Absinthe.Schema.Notation @desc "A local user of Mobilizon" diff --git a/priv/repo/migrations/20190114162055_remove_address_type.exs b/priv/repo/migrations/20190114162055_remove_address_type.exs new file mode 100644 index 000000000..ead2109fe --- /dev/null +++ b/priv/repo/migrations/20190114162055_remove_address_type.exs @@ -0,0 +1,11 @@ +defmodule Mobilizon.Repo.Migrations.RemoveAddressType do + use Ecto.Migration + + def up do + alter table(:events) do + remove(:address_type) + end + execute "DROP TYPE address_type" + rename table(:events), :phone, to: :phone_address + end +end diff --git a/test/mobilizon_web/resolvers/event_resolver_test.exs b/test/mobilizon_web/resolvers/event_resolver_test.exs index e82a1e10b..80a3ad207 100644 --- a/test/mobilizon_web/resolvers/event_resolver_test.exs +++ b/test/mobilizon_web/resolvers/event_resolver_test.exs @@ -118,8 +118,7 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do description: "it will be fine", begins_on: "#{DateTime.utc_now() |> DateTime.to_iso8601()}", organizer_actor_username: "#{actor.preferred_username}", - category: "#{category.title}", - address_type: #{"OTHER"} + category: "#{category.title}" ) { title, uuid From 3230381be40b0c9541d4c6e1a0b6560ca7f8da00 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 14 Jan 2019 18:12:52 +0100 Subject: [PATCH 3/3] Remove last occurences of address_type Signed-off-by: Thomas Citharel --- js/src/components/Event/Create.vue | 223 +++++++++--------- js/src/graphql/event.ts | 8 +- .../20180702150922_add_address_type.exs | 4 - .../20190114162055_remove_address_type.exs | 7 +- 4 files changed, 117 insertions(+), 125 deletions(-) diff --git a/js/src/components/Event/Create.vue b/js/src/components/Event/Create.vue index 3796aa61a..f24f5b4de 100644 --- a/js/src/components/Event/Create.vue +++ b/js/src/components/Event/Create.vue @@ -8,14 +8,8 @@ - - - + + @@ -33,7 +27,7 @@ types="geocode" v-on:placechanged="getAddressData" > - --> + --> - + > Create event @@ -66,125 +59,135 @@ diff --git a/js/src/graphql/event.ts b/js/src/graphql/event.ts index 14906976f..d42ef03f8 100644 --- a/js/src/graphql/event.ts +++ b/js/src/graphql/event.ts @@ -85,19 +85,13 @@ export const CREATE_EVENT = gql` $organizerActorId: Int!, $categoryId: Int!, $beginsOn: DateTime!, - $addressType: AddressType!, ) { createEvent( title: $title, description: $description, beginsOn: $beginsOn, organizerActorId: $organizerActorId, - categoryId: $categoryId, - addressType: $addressType) { - uuid, - title, - description, - } + categoryId: $categoryId } `; diff --git a/priv/repo/migrations/20180702150922_add_address_type.exs b/priv/repo/migrations/20180702150922_add_address_type.exs index d9085e08d..253ede470 100644 --- a/priv/repo/migrations/20180702150922_add_address_type.exs +++ b/priv/repo/migrations/20180702150922_add_address_type.exs @@ -2,9 +2,7 @@ defmodule Mobilizon.Repo.Migrations.AddAddressType do use Ecto.Migration def up do - Mobilizon.Events.AddressTypeEnum.create_type alter table(:events) do - add :address_type, :address_type add :online_address, :string add :phone, :string end @@ -17,11 +15,9 @@ defmodule Mobilizon.Repo.Migrations.AddAddressType do def down do alter table(:events) do - remove :address_type remove :online_address remove :phone end - 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/20190114162055_remove_address_type.exs b/priv/repo/migrations/20190114162055_remove_address_type.exs index ead2109fe..74b73b7a3 100644 --- a/priv/repo/migrations/20190114162055_remove_address_type.exs +++ b/priv/repo/migrations/20190114162055_remove_address_type.exs @@ -1,11 +1,10 @@ defmodule Mobilizon.Repo.Migrations.RemoveAddressType do use Ecto.Migration + require Logger def up do - alter table(:events) do - remove(:address_type) - end - execute "DROP TYPE address_type" + execute "DROP TYPE IF EXISTS address_type" + execute "ALTER TABLE \"events\" DROP COLUMN IF EXISTS address_type" rename table(:events), :phone, to: :phone_address end end