diff --git a/js/src/components/Tag.vue b/js/src/components/Tag.vue
index 64eff4b5d..2fcf28699 100644
--- a/js/src/components/Tag.vue
+++ b/js/src/components/Tag.vue
@@ -17,7 +17,8 @@ span.tag {
background: $purple-3;
color: $violet-2;
text-transform: uppercase;
- &::before {
+
+ &:not(.category)::before {
content: "#";
}
}
diff --git a/js/src/graphql/event.ts b/js/src/graphql/event.ts
index d2dcc4b3b..605d9ddc3 100644
--- a/js/src/graphql/event.ts
+++ b/js/src/graphql/event.ts
@@ -23,6 +23,7 @@ const FULL_EVENT_FRAGMENT = gql`
joinOptions
draft
language
+ category
picture {
id
url
@@ -203,7 +204,7 @@ export const CREATE_EVENT = gql`
$picture: MediaInput
$onlineAddress: String
$phoneAddress: String
- $category: String
+ $category: EventCategory
$physicalAddress: AddressInput
$options: EventOptionsInput
$contacts: [Contact]
@@ -253,7 +254,7 @@ export const EDIT_EVENT = gql`
$phoneAddress: String
$organizerActorId: ID
$attributedToId: ID
- $category: String
+ $category: EventCategory
$physicalAddress: AddressInput
$options: EventOptionsInput
$contacts: [Contact]
diff --git a/js/src/graphql/search.ts b/js/src/graphql/search.ts
index 9f4462d3e..22e2d9a33 100644
--- a/js/src/graphql/search.ts
+++ b/js/src/graphql/search.ts
@@ -11,6 +11,7 @@ export const SEARCH_EVENTS_AND_GROUPS = gql`
$tags: String
$term: String
$type: EventType
+ $category: String
$beginsOn: DateTime
$endsOn: DateTime
$eventPage: Int
@@ -23,6 +24,7 @@ export const SEARCH_EVENTS_AND_GROUPS = gql`
tags: $tags
term: $term
type: $type
+ category: $category
beginsOn: $beginsOn
endsOn: $endsOn
page: $eventPage
diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json
index 4399aa369..236522afd 100644
--- a/js/src/i18n/en_US.json
+++ b/js/src/i18n/en_US.json
@@ -1306,5 +1306,23 @@
"IP Address": "IP Address",
"Last seen on": "Last seen on",
"No user matches the filters": "No user matches the filters",
- "Reset filters": "Reset filters"
+ "Reset filters": "Reset filters",
+ "Arts": "Arts",
+ "Book Clubs": "Book Clubs",
+ "Business": "Business",
+ "Causes": "Causes",
+ "Comedy": "Comedy",
+ "Crafts": "Crafts",
+ "Food & Drink": "Food & Drink",
+ "Health": "Health",
+ "Music": "Music",
+ "Auto, Boat & Air": "Auto, Boat & Air",
+ "Community": "Community",
+ "Family & Education": "Family & Education",
+ "Fashion & Beauty": "Fashion & Beauty",
+ "Film & Media": "Film & Media",
+ "Games": "Games",
+ "Category": "Category",
+ "Select a category": "Select a category",
+ "Any category": "Any category"
}
diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json
index 839266cbf..b3fc7b805 100644
--- a/js/src/i18n/fr_FR.json
+++ b/js/src/i18n/fr_FR.json
@@ -1305,5 +1305,23 @@
"{timezoneLongName} ({timezoneShortName})": "{timezoneLongName} ({timezoneShortName})",
"{title} ({count} todos)": "{title} ({count} todos)",
"{username} was invited to {group}": "{username} a été invité à {group}",
- "© The OpenStreetMap Contributors": "© Les Contributeur⋅ices OpenStreetMap"
+ "© The OpenStreetMap Contributors": "© Les Contributeur⋅ices OpenStreetMap",
+ "Arts": "Arts",
+ "Book Clubs": "Clubs de lecture",
+ "Business": "Entreprises",
+ "Causes": "Causes",
+ "Comedy": "Comédie",
+ "Crafts": "Artisanat",
+ "Food & Drink": "Alimentation et boissons",
+ "Health": "Santé",
+ "Music": "Musique",
+ "Auto, Boat & Air": "Automobile, bateaux et aéronautique",
+ "Community": "Communauté",
+ "Family & Education": "Famille et éducation",
+ "Fashion & Beauty": "Mode et beauté",
+ "Film & Media": "Films et médias",
+ "Games": "Jeux",
+ "Category": "Catégorie",
+ "Select a category": "Choisissez une categorie",
+ "Any category": "N'importe quelle catégorie"
}
diff --git a/js/src/types/enums.ts b/js/src/types/enums.ts
index 2f05bd0d0..1061d196b 100644
--- a/js/src/types/enums.ts
+++ b/js/src/types/enums.ts
@@ -72,14 +72,6 @@ export enum EventVisibilityJoinOptions {
LIMITED = "LIMITED",
}
-export enum Category {
- BUSINESS = "business",
- CONFERENCE = "conference",
- BIRTHDAY = "birthday",
- DEMONSTRATION = "demonstration",
- MEETING = "meeting",
-}
-
export enum LoginErrorCode {
NEED_TO_LOGIN = "need_to_login",
}
diff --git a/js/src/types/event.model.ts b/js/src/types/event.model.ts
index e091af117..e06703665 100644
--- a/js/src/types/event.model.ts
+++ b/js/src/types/event.model.ts
@@ -53,6 +53,7 @@ interface IEventEditJSON {
options: IEventOptions;
contacts: { id?: string }[];
metadata: IEventMetadata[];
+ category: string;
}
export interface IEvent {
@@ -91,6 +92,7 @@ export interface IEvent {
metadata: IEventMetadata[];
contacts: IActor[];
language: string;
+ category: string;
toEditJSON(): IEventEditJSON;
}
@@ -166,6 +168,8 @@ export class EventModel implements IEvent {
metadata: IEventMetadata[] = [];
+ category = "MEETING";
+
constructor(hash?: IEvent | IEditableEvent) {
if (!hash) return;
@@ -214,6 +218,7 @@ export class EventModel implements IEvent {
this.tags = hash.tags;
this.metadata = hash.metadata;
this.language = hash.language;
+ this.category = hash.category;
if (hash.options) this.options = hash.options;
}
@@ -240,6 +245,7 @@ export function toEditJSON(event: IEditableEvent): IEventEditJSON {
beginsOn: event.beginsOn ? event.beginsOn.toISOString() : null,
endsOn: event.endsOn ? event.endsOn.toISOString() : null,
status: event.status,
+ category: event.category,
visibility: event.visibility,
joinOptions: event.joinOptions,
draft: event.draft,
diff --git a/js/src/utils/categories.ts b/js/src/utils/categories.ts
new file mode 100644
index 000000000..981659c4c
--- /dev/null
+++ b/js/src/utils/categories.ts
@@ -0,0 +1,68 @@
+import { i18n } from "@/utils/i18n";
+
+export const eventCategories = [
+ {
+ id: "ARTS",
+ label: i18n.t("Arts"),
+ icon: "palette",
+ },
+ {
+ id: "BOOK_CLUBS",
+ label: i18n.t("Book Clubs"),
+ icon: "favourite-book",
+ },
+ {
+ id: "BUSINESS",
+ label: i18n.t("Business"),
+ },
+ {
+ id: "CAUSES",
+ label: i18n.t("Causes"),
+ },
+ {
+ id: "COMEDY",
+ label: i18n.t("Comedy"),
+ },
+ {
+ id: "CRAFTS",
+ label: i18n.t("Crafts"),
+ },
+ {
+ id: "FOOD_DRINK",
+ label: i18n.t("Food & Drink"),
+ },
+ {
+ id: "HEALTH",
+ label: i18n.t("Health"),
+ },
+ {
+ id: "MUSIC",
+ label: i18n.t("Music"),
+ },
+ {
+ id: "AUTO_BOAT_AIR",
+ label: i18n.t("Auto, Boat & Air"),
+ },
+ {
+ id: "COMMUNITY",
+ label: i18n.t("Community"),
+ },
+ {
+ id: "FAMILY_EDUCATION",
+ label: i18n.t("Family & Education"),
+ },
+ {
+ id: "FASHION_BEAUTY",
+ label: i18n.t("Fashion & Beauty"),
+ },
+ {
+ id: "FILM_MEDIA",
+ label: i18n.t("Film & Media"),
+ },
+ {
+ id: "GAMES",
+ label: i18n.t("Games"),
+ },
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+].sort(({ label: label1 }, { label: label2 }) => label1.localeCompare(label2));
diff --git a/js/src/views/Event/Edit.vue b/js/src/views/Event/Edit.vue
index efb20bf29..9a3e0c0dd 100644
--- a/js/src/views/Event/Edit.vue
+++ b/js/src/views/Event/Edit.vue
@@ -32,7 +32,28 @@
/>
-
+
+
+
+
+
+
+
+
-
+
+ {{
+ eventCategory
+ }}
{
+ return eventCategory.id === this.event?.category;
+ })?.label as string;
+ }
}
diff --git a/lib/graphql/schema.ex b/lib/graphql/schema.ex
index f8b143d05..e89641b4a 100644
--- a/lib/graphql/schema.ex
+++ b/lib/graphql/schema.ex
@@ -22,12 +22,15 @@ defmodule Mobilizon.GraphQL.Schema do
alias Mobilizon.Events.{Event, Participant}
alias Mobilizon.GraphQL.Middleware.{CurrentActorProvider, ErrorHandler}
alias Mobilizon.GraphQL.Schema
+ alias Mobilizon.GraphQL.Schema.Custom
alias Mobilizon.Storage.Repo
+ @pipeline_modifier Custom.EnumTypes
+
import_types(Absinthe.Type.Custom)
import_types(Absinthe.Plug.Types)
- import_types(Schema.Custom.UUID)
- import_types(Schema.Custom.Point)
+ import_types(Custom.UUID)
+ import_types(Custom.Point)
import_types(Schema.ActivityType)
import_types(Schema.UserType)
diff --git a/lib/graphql/schema/custom/enum_types.ex b/lib/graphql/schema/custom/enum_types.ex
new file mode 100644
index 000000000..781449ec7
--- /dev/null
+++ b/lib/graphql/schema/custom/enum_types.ex
@@ -0,0 +1,109 @@
+defmodule Mobilizon.GraphQL.Schema.Custom.EnumTypes do
+ alias Absinthe.Blueprint.Schema
+ alias Absinthe.Schema.Notation
+ alias Absinthe.{Blueprint, Pipeline, Phase}
+
+ @categories [
+ %{
+ id: :arts,
+ label: "ARTS"
+ },
+ %{
+ id: :book_clubs,
+ label: "BOOK_CLUBS"
+ },
+ %{
+ id: :business,
+ label: "BUSINESS"
+ },
+ %{
+ id: :causes,
+ label: "CAUSES"
+ },
+ %{
+ id: :comedy,
+ label: "COMEDY"
+ },
+ %{
+ id: :crafts,
+ label: "CRAFTS"
+ },
+ %{
+ id: :food_drink,
+ label: "FOOD_DRINK"
+ },
+ %{
+ id: :health,
+ label: "HEALTH"
+ },
+ %{
+ id: :music,
+ label: "MUSIC"
+ },
+ %{
+ id: :auto_boat_air,
+ label: "AUTO_BOAT_AIR"
+ },
+ %{
+ id: :community,
+ label: "COMMUNITY"
+ },
+ %{
+ id: :family_education,
+ label: "FAMILY_EDUCATION"
+ },
+ %{
+ id: :fashion_beauty,
+ label: "FASHION_BEAUTY"
+ },
+ %{
+ id: :film_media,
+ label: "FILM_MEDIA"
+ },
+ %{
+ id: :games,
+ label: "GAMES"
+ },
+ # Legacy default value
+ %{
+ id: :meeting,
+ label: "MEETING"
+ }
+ ]
+
+ def pipeline(pipeline) do
+ Pipeline.insert_after(pipeline, Phase.Schema.TypeImports, __MODULE__)
+ end
+
+ def run(blueprint = %Blueprint{}, _) do
+ %{schema_definitions: [schema]} = blueprint
+
+ new_enum = build_dynamic_enum()
+
+ schema =
+ Map.update!(schema, :type_definitions, fn type_definitions ->
+ [new_enum | type_definitions]
+ end)
+
+ {:ok, %{blueprint | schema_definitions: [schema]}}
+ end
+
+ def build_dynamic_enum() do
+ %Schema.EnumTypeDefinition{
+ name: "EventCategory",
+ identifier: :event_category,
+ module: __MODULE__,
+ __reference__: Notation.build_reference(__ENV__),
+ values:
+ Enum.map(@categories, fn %{id: id, label: label} ->
+ %Schema.EnumValueDefinition{
+ identifier: id,
+ value: label,
+ name: label,
+ module: __MODULE__,
+ __reference__: Notation.build_reference(__ENV__)
+ }
+ end)
+ }
+ end
+end
diff --git a/lib/graphql/schema/event.ex b/lib/graphql/schema/event.ex
index 503c6e7e9..9a4dd9ea3 100644
--- a/lib/graphql/schema/event.ex
+++ b/lib/graphql/schema/event.ex
@@ -66,7 +66,7 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
description: "The event's tags"
)
- field(:category, :string, description: "The event's category")
+ field(:category, :event_category, description: "The event's category")
field(:draft, :boolean, description: "Whether or not the event is a draft")
@@ -399,7 +399,11 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
arg(:attributed_to_id, :id, description: "Who the event is attributed to ID (often a group)")
- arg(:category, :string, default_value: "meeting", description: "The event's category")
+ arg(:category, :event_category,
+ default_value: "MEETING",
+ description: "The event's category"
+ )
+
arg(:physical_address, :address_input, description: "The event's physical address")
arg(:options, :event_options_input, default_value: %{}, description: "The event options")
arg(:metadata, list_of(:event_metadata_input), description: "The event metadata")
@@ -448,7 +452,7 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
arg(:attributed_to_id, :id, description: "Who the event is attributed to ID (often a group)")
- arg(:category, :string, description: "The event's category")
+ arg(:category, :event_category, description: "The event's category")
arg(:physical_address, :address_input, description: "The event's physical address")
arg(:options, :event_options_input, description: "The event options")
arg(:metadata, list_of(:event_metadata_input), description: "The event metadata")
diff --git a/lib/graphql/schema/search.ex b/lib/graphql/schema/search.ex
index db0c7be58..2da1d8fa4 100644
--- a/lib/graphql/schema/search.ex
+++ b/lib/graphql/schema/search.ex
@@ -93,6 +93,7 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do
arg(:tags, :string, description: "A comma-separated string listing the tags")
arg(:location, :string, description: "A geohash for coordinates")
arg(:type, :event_type, description: "Whether the event is online or in person")
+ arg(:category, :string, description: "The category for the event")
arg(:radius, :float,
default_value: 50,
diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex
index 72656e1d7..6d4b1a50f 100644
--- a/lib/mobilizon/events/events.ex
+++ b/lib/mobilizon/events/events.ex
@@ -54,14 +54,6 @@ defmodule Mobilizon.Events do
:cancelled
])
- defenum(EventCategory, :event_category, [
- :business,
- :conference,
- :birthday,
- :demonstration,
- :meeting
- ])
-
defenum(ParticipantRole, :participant_role, [
:not_approved,
:not_confirmed,
@@ -536,6 +528,7 @@ defmodule Mobilizon.Events do
|> events_for_search_query()
|> events_for_begins_on(args)
|> events_for_ends_on(args)
+ |> events_for_category(args)
|> events_for_tags(args)
|> events_for_location(args)
|> filter_online(args)
@@ -1313,6 +1306,13 @@ defmodule Mobilizon.Events do
end
end
+ @spec events_for_category(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
+ defp events_for_category(query, %{category: category}) when is_valid_string(category) do
+ where(query, [q], q.category == ^category)
+ end
+
+ defp events_for_category(query, _args), do: query
+
@spec events_for_tags(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
defp events_for_tags(query, %{tags: tags}) when is_valid_string(tags) do
query
diff --git a/mix.exs b/mix.exs
index 20375bb1d..882bd7b49 100644
--- a/mix.exs
+++ b/mix.exs
@@ -299,7 +299,6 @@ defmodule Mobilizon.Mixfile do
Mobilizon.Events.Tag,
Mobilizon.Events.TagRelations,
Mobilizon.Events.Track,
- Mobilizon.Events.EventCategory,
Mobilizon.Events.EventStatus,
Mobilizon.Events.EventVisibility,
Mobilizon.Events.JoinOptions,
diff --git a/priv/repo/migrations/20220328153640_set_all_events_category_to_meeting.exs b/priv/repo/migrations/20220328153640_set_all_events_category_to_meeting.exs
new file mode 100644
index 000000000..b51fa3b9e
--- /dev/null
+++ b/priv/repo/migrations/20220328153640_set_all_events_category_to_meeting.exs
@@ -0,0 +1,11 @@
+defmodule Mobilizon.Storage.Repo.Migrations.SetAllEventsCategoryToMeeting do
+ use Ecto.Migration
+
+ def up do
+ Ecto.Migration.execute("UPDATE events SET category = 'MEETING'")
+ end
+
+ def down do
+ Ecto.Migration.execute("UPDATE events SET category = 'meeting' WHERE category = 'MEETING'")
+ end
+end
diff --git a/test/graphql/resolvers/event_test.exs b/test/graphql/resolvers/event_test.exs
index 23b1bb8ec..79cdc16ae 100644
--- a/test/graphql/resolvers/event_test.exs
+++ b/test/graphql/resolvers/event_test.exs
@@ -21,7 +21,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
begins_on: DateTime.utc_now() |> DateTime.truncate(:second),
uuid: "b5126423-f1af-43e4-a923-002a03003ba4",
url: "some url",
- category: "meeting"
+ category: "MEETING"
}
@find_event_query """
diff --git a/test/graphql/resolvers/participant_test.exs b/test/graphql/resolvers/participant_test.exs
index 80d3c7b06..52194029f 100644
--- a/test/graphql/resolvers/participant_test.exs
+++ b/test/graphql/resolvers/participant_test.exs
@@ -20,7 +20,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do
|> DateTime.truncate(:second),
uuid: "b5126423-f1af-43e4-a923-002a03003ba4",
url: "some url",
- category: "meeting",
+ category: "MEETING",
options: %{}
}
diff --git a/test/mobilizon/events/events_test.exs b/test/mobilizon/events/events_test.exs
index efc0ae550..1e76249e0 100644
--- a/test/mobilizon/events/events_test.exs
+++ b/test/mobilizon/events/events_test.exs
@@ -17,7 +17,7 @@ defmodule Mobilizon.EventsTest do
title: "some title",
url: "some url",
uuid: "b5126423-f1af-43e4-a923-002a03003ba4",
- category: "meeting"
+ category: "MEETING"
}
describe "list_events/5" do