diff --git a/js/src/App.vue b/js/src/App.vue index ac3070a21..79b809b51 100644 --- a/js/src/App.vue +++ b/js/src/App.vue @@ -49,12 +49,6 @@ export default class App extends Vue { route: "GroupList", role: null }, - { - icon: "content_copy", - text: "Categories", - route: "CategoryList", - role: "ROLE_ADMIN" - }, { icon: "settings", text: "Settings", role: "ROLE_USER" }, { icon: "chat_bubble", text: "Send feedback", role: "ROLE_USER" }, { icon: "help", text: "Help", role: null }, diff --git a/js/src/graphql/category.ts b/js/src/graphql/category.ts deleted file mode 100644 index 3966ff137..000000000 --- a/js/src/graphql/category.ts +++ /dev/null @@ -1,29 +0,0 @@ -import gql from 'graphql-tag'; - -export const FETCH_CATEGORIES = gql` -query { - categories { - id, - title, - description, - picture { - url, - }, - } -} -`; - -export const CREATE_CATEGORY = gql` - mutation createCategory($title: String!, $description: String!, $picture: Upload!) { - createCategory(title: $title, description: $description, picture: $picture) { - id, - title, - description, - picture { - url, - url_thumbnail - }, - }, - }, - -`; diff --git a/js/src/graphql/event.ts b/js/src/graphql/event.ts index b5989eeb0..75f908934 100644 --- a/js/src/graphql/event.ts +++ b/js/src/graphql/event.ts @@ -25,6 +25,7 @@ export const FETCH_EVENT = gql` thumbnail, large_image, publish_at, + category, # online_address, # phone_address, organizerActor { @@ -39,10 +40,7 @@ export const FETCH_EVENT = gql` # }, participants { ${participantQuery} - }, - category { - title, - }, + } } } `; @@ -75,9 +73,7 @@ export const FETCH_EVENTS = gql` preferredUsername, name, }, - category { - title, - }, + category, participants { ${participantQuery} } @@ -112,9 +108,9 @@ export const EDIT_EVENT = gql` $title: String!, $description: String!, $organizerActorId: Int!, - $categoryId: Int! + $category: String! ) { - EditEvent(title: $title, description: $description, organizerActorId: $organizerActorId, categoryId: $categoryId) { + EditEvent(title: $title, description: $description, organizerActorId: $organizerActorId, category: $category) { uuid } } diff --git a/js/src/router/category.ts b/js/src/router/category.ts deleted file mode 100644 index 1dee45401..000000000 --- a/js/src/router/category.ts +++ /dev/null @@ -1,22 +0,0 @@ -import CategoryList from '@/views/Category/List.vue'; -import CreateCategory from '@/views/Category/Create.vue'; - -export enum CategoryRouteName { - CATEGORY_LIST = 'CategoryList', - CREATE_CATEGORY = 'CreateCategory', -} - -export const categoryRoutes = [ - { - path: '/category', - name: CategoryRouteName.CATEGORY_LIST, - component: CategoryList, - meta: { requiredAuth: false }, - }, - { - path: '/category/create', - name: CategoryRouteName.CREATE_CATEGORY, - component: CreateCategory, - meta: { requiredAuth: true }, - }, -]; diff --git a/js/src/router/index.ts b/js/src/router/index.ts index aa259fcd4..0663b53d4 100644 --- a/js/src/router/index.ts +++ b/js/src/router/index.ts @@ -5,7 +5,6 @@ import Home from '@/views/Home.vue'; import { UserRouteName, userRoutes } from './user'; import { EventRouteName, eventRoutes } from '@/router/event'; import { ActorRouteName, actorRoutes } from '@/router/actor'; -import { CategoryRouteName, categoryRoutes } from '@/router/category'; Vue.use(Router); @@ -20,7 +19,6 @@ export const RouteName = { ...GlobalRouteName, ...UserRouteName, ...EventRouteName, - ...CategoryRouteName, ...ActorRouteName, }; @@ -30,7 +28,6 @@ const router = new Router({ routes: [ ...userRoutes, ...eventRoutes, - ...categoryRoutes, ...actorRoutes, { diff --git a/js/src/types/event.model.ts b/js/src/types/event.model.ts index 48c713d13..42893dec8 100644 --- a/js/src/types/event.model.ts +++ b/js/src/types/event.model.ts @@ -27,10 +27,12 @@ export enum ParticipantRole { CREATOR = 'creator', } -export interface ICategory { - title: string; - description: string; - picture: string; +export enum Category { + BUSINESS = 'business', + CONFERENCE = 'conference', + BIRTHDAY = 'birthday', + DEMONSTRATION = 'demonstration', + MEETING = 'meeting', } export interface IParticipant { @@ -47,7 +49,7 @@ export interface IEvent { title: string; description: string; - category: ICategory; + category: Category; begins_on: Date; ends_on: Date; diff --git a/js/src/views/Category/Create.vue b/js/src/views/Category/Create.vue deleted file mode 100644 index 6617bb72d..000000000 --- a/js/src/views/Category/Create.vue +++ /dev/null @@ -1,75 +0,0 @@ -<template> - <section> - <h1 class="title"> - <translate>Create a new category</translate> - </h1> - <div class="columns"> - <form class="column" @submit="submit"> - <b-field :label="$gettext('Name of the category')"> - <b-input aria-required="true" required v-model="category.title"/> - </b-field> - - <b-field :label="$gettext('Description')"> - <b-input type="textarea" v-model="category.description"/> - </b-field> - - <b-field class="file"> - <b-upload v-model="file" @input="onFilePicked"> - <a class="button is-primary"> - <b-icon icon="upload"></b-icon> - <span> - <translate>Click to upload</translate> - </span> - </a> - </b-upload> - <span class="file-name" v-if="file">{{ this.image.name }}</span> - </b-field> - - <button class="button is-primary"> - <translate>Create the category</translate> - </button> - </form> - </div> - </section> -</template> - -<script lang="ts"> -import { CREATE_CATEGORY } from "@/graphql/category"; -import { Component, Vue } from "vue-property-decorator"; -import { ICategory } from "@/types/event.model"; - -/** - * TODO : No picture is uploaded ATM - */ - -@Component -export default class CreateCategory extends Vue { - category!: ICategory; - image = { - name: "" - } as { name: string }; - file: any = null; - - create() { - this.$apollo - .mutate({ - mutation: CREATE_CATEGORY, - variables: this.category - }) - .then(data => { - console.log(data); - }) - .catch(error => { - console.error(error); - }); - } - - // TODO : Check if we can upload as soon as file is picked and purge files not validated - onFilePicked(e) { - if (e === undefined || e.name.lastIndexOf(".") <= 0) { - console.error("File is incorrect"); - } - this.image.name = e.name; - } -} -</script> diff --git a/js/src/views/Category/List.vue b/js/src/views/Category/List.vue deleted file mode 100644 index 0fb1a6e70..000000000 --- a/js/src/views/Category/List.vue +++ /dev/null @@ -1,55 +0,0 @@ -<template> - <section> - <h1 class="title"> - <translate>Category List</translate> - </h1> - <b-loading :active.sync="$apollo.loading"></b-loading> - <div class="columns"> - <div class="column card" v-for="category in categories" :key="category.id"> - <div class="card-image"> - <figure class="image is-4by3"> - <img v-if="category.picture.url" :src="HTTP_ENDPOINT + category.picture.url"> - </figure> - </div> - <div class="card-content"> - <h2 class="title is-4">{{ category.title }}</h2> - <p>{{ category.description }}</p> - </div> - </div> - </div> - </section> -</template> - -<script lang="ts"> -import { FETCH_CATEGORIES } from "@/graphql/category"; -import { Component, Vue } from "vue-property-decorator"; - -// TODO : remove this hardcode - -@Component({ - apollo: { - categories: { - query: FETCH_CATEGORIES - } - } -}) -export default class List extends Vue { - categories = []; - loading = true; - HTTP_ENDPOINT = "http://localhost:4000"; - - deleteCategory(categoryId) { - const router = this.$router; - // FIXME: remove eventFetch - // eventFetch(`/categories/${categoryId}`, this.$store, { method: 'DELETE' }) - // .then(() => { - // this.categories = this.categories.filter(category => category.id !== categoryId); - // router.push('/category'); - // }); - } -} -</script> - -<!-- Add "scoped" attribute to limit CSS to this component only --> -<style scoped> -</style> diff --git a/js/src/views/Event/Create.vue b/js/src/views/Event/Create.vue index b674f9f66..60e8e55b0 100644 --- a/js/src/views/Event/Create.vue +++ b/js/src/views/Event/Create.vue @@ -1,3 +1,4 @@ +import {Category} from "../../types/event.model"; import {EventJoinOptions} from "../../types/event.model"; <template> <section> @@ -18,8 +19,8 @@ import {EventJoinOptions} from "../../types/event.model"; <option v-for="category in categories" :value="category" - :key="category.title" - >{{ category.title }}</option> + :key="category" + >{{ $gettext(category) }}</option> </b-select> </b-field> @@ -32,30 +33,24 @@ import {EventJoinOptions} from "../../types/event.model"; </template> <script lang="ts"> - // import Location from '@/components/Location'; - import VueMarkdown from "vue-markdown"; - import {CREATE_EVENT, EDIT_EVENT} from "@/graphql/event"; - import {FETCH_CATEGORIES} from "@/graphql/category"; - import {Component, Prop, Vue} from "vue-property-decorator"; - import {EventJoinOptions, EventStatus, EventVisibility, ICategory, IEvent} from "@/types/event.model"; - import {LOGGED_PERSON} from "@/graphql/actor"; - import {IPerson} from "@/types/actor.model"; + // import Location from '@/components/Location'; + import VueMarkdown from "vue-markdown"; + import {CREATE_EVENT, EDIT_EVENT} from "@/graphql/event"; + import {Component, Prop, Vue} from "vue-property-decorator"; + import {Category, EventJoinOptions, EventStatus, EventVisibility, IEvent} from "@/types/event.model"; + import {LOGGED_PERSON} from "@/graphql/actor"; + import {IPerson} from "@/types/actor.model"; - @Component({ + @Component({ components: { VueMarkdown - }, - apollo: { - categories: { - query: FETCH_CATEGORIES - } } }) export default class CreateEvent extends Vue { @Prop({ required: false, type: String }) uuid!: string; loggedPerson!: IPerson; - categories: ICategory[] = []; + categories: string[] = Object.keys(Category); event!: IEvent; // FIXME: correctly type an event // created() { @@ -77,7 +72,7 @@ export default class CreateEvent extends Vue { description: "", begins_on: new Date(), ends_on: new Date(), - category: this.categories[0], + category: Category.MEETING, participants: [], uuid: "", url: "", @@ -102,7 +97,7 @@ export default class CreateEvent extends Vue { title: this.event.title, description: this.event.description, beginsOn: this.event.begins_on, - category: this.event.category.title, + category: this.event.category, organizerActorId: this.event.organizerActor.id } }) diff --git a/js/src/views/Event/Event.vue b/js/src/views/Event/Event.vue index bc946442d..9510dcf48 100644 --- a/js/src/views/Event/Event.vue +++ b/js/src/views/Event/Event.vue @@ -10,7 +10,7 @@ </div> <div class="card-content"> <span>{{ event.begins_on | formatDay }}</span> - <span class="tag is-primary">{{ event.category.title }}</span> + <span class="tag is-primary">{{ event.category }}</span> <h1 class="title">{{ event.title }}</h1> <router-link :to="{name: 'Profile', params: { name: event.organizerActor.preferredUsername } }" diff --git a/lib/mobilizon/events/category.ex b/lib/mobilizon/events/category.ex deleted file mode 100644 index a9afeea2f..000000000 --- a/lib/mobilizon/events/category.ex +++ /dev/null @@ -1,26 +0,0 @@ -defmodule Mobilizon.Events.Category do - @moduledoc """ - Represents a category for events - """ - use Ecto.Schema - import Ecto.Changeset - alias Mobilizon.Events.Category - use Arc.Ecto.Schema - - schema "categories" do - field(:description, :string) - field(:picture, MobilizonWeb.Uploaders.Category.Type) - field(:title, :string, null: false) - - timestamps() - end - - @doc false - def changeset(%Category{} = category, attrs) do - category - |> cast(attrs, [:title, :description]) - |> cast_attachments(attrs, [:picture]) - |> validate_required([:title]) - |> unique_constraint(:title) - end -end diff --git a/lib/mobilizon/events/event.ex b/lib/mobilizon/events/event.ex index 98a82876f..05fbfe3a8 100644 --- a/lib/mobilizon/events/event.ex +++ b/lib/mobilizon/events/event.ex @@ -19,13 +19,21 @@ defenum(Mobilizon.Events.EventStatusEnum, :event_status_type, [ :cancelled ]) +defenum(Mobilizon.Event.EventCategoryEnum, :event_category_type, [ + :business, + :conference, + :birthday, + :demonstration, + :meeting +]) + defmodule Mobilizon.Events.Event do @moduledoc """ Represents an event """ use Ecto.Schema import Ecto.Changeset - alias Mobilizon.Events.{Event, Participant, Tag, Category, Session, Track} + alias Mobilizon.Events.{Event, Participant, Tag, Session, Track} alias Mobilizon.Actors.Actor alias Mobilizon.Addresses.Address @@ -45,10 +53,10 @@ defmodule Mobilizon.Events.Event do field(:uuid, Ecto.UUID, default: Ecto.UUID.generate()) field(:online_address, :string) field(:phone_address, :string) + field(:category, :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") - belongs_to(:category, Category) many_to_many(:participants, Actor, join_through: Participant) has_many(:tracks, Track) has_many(:sessions, Session) @@ -67,7 +75,7 @@ defmodule Mobilizon.Events.Event do :begins_on, :ends_on, :organizer_actor_id, - :category_id, + :category, :status, :visibility, :thumbnail, @@ -83,7 +91,7 @@ defmodule Mobilizon.Events.Event do :title, :begins_on, :organizer_actor_id, - :category_id, + :category, :url, :uuid ]) diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex index 6fc784991..6bf3ea1ec 100644 --- a/lib/mobilizon/events/events.ex +++ b/lib/mobilizon/events/events.ex @@ -27,7 +27,6 @@ defmodule Mobilizon.Events do order_by: [desc: :id], preload: [ :organizer_actor, - :category, :sessions, :tracks, :tags, @@ -145,7 +144,6 @@ defmodule Mobilizon.Events do where: e.uuid == ^uuid and e.visibility in [^:public, ^:unlisted], preload: [ :organizer_actor, - :category, :sessions, :tracks, :tags, @@ -164,7 +162,6 @@ defmodule Mobilizon.Events do Repo.preload(event, [ :organizer_actor, - :category, :sessions, :tracks, :tags, @@ -182,7 +179,6 @@ defmodule Mobilizon.Events do where: e.url == ^url and e.visibility in [^:public, ^:unlisted], preload: [ :organizer_actor, - :category, :sessions, :tracks, :tags, @@ -205,7 +201,6 @@ defmodule Mobilizon.Events do where: e.url == ^url and e.visibility in [^:public, ^:unlisted], preload: [ :organizer_actor, - :category, :sessions, :tracks, :tags, @@ -350,110 +345,6 @@ defmodule Mobilizon.Events do Event.changeset(event, %{}) end - alias Mobilizon.Events.Category - - @doc """ - Returns the list of categories. - - ## Examples - - iex> list_categories() - [%Category{}, ...] - - """ - def list_categories(page \\ nil, limit \\ nil) do - Repo.all( - Category - |> paginate(page, limit) - ) - end - - @doc """ - Gets a single category. - - Raises `Ecto.NoResultsError` if the Category does not exist. - - ## Examples - - iex> get_category!(123) - %Category{} - - iex> get_category!(456) - ** (Ecto.NoResultsError) - - """ - def get_category!(id), do: Repo.get!(Category, id) - - @spec get_category_by_title(String.t()) :: Category.t() | nil - def get_category_by_title(title) when is_binary(title) do - Repo.get_by(Category, title: title) - end - - @doc """ - Creates a category. - - ## Examples - - iex> create_category(%{field: value}) - {:ok, %Category{}} - - iex> create_category(%{field: bad_value}) - {:error, %Ecto.Changeset{}} - - """ - def create_category(attrs \\ %{}) do - %Category{} - |> Category.changeset(attrs) - |> Repo.insert() - end - - @doc """ - Updates a category. - - ## Examples - - iex> update_category(category, %{field: new_value}) - {:ok, %Category{}} - - iex> update_category(category, %{field: bad_value}) - {:error, %Ecto.Changeset{}} - - """ - def update_category(%Category{} = category, attrs) do - category - |> Category.changeset(attrs) - |> Repo.update() - end - - @doc """ - Deletes a Category. - - ## Examples - - iex> delete_category(category) - {:ok, %Category{}} - - iex> delete_category(category) - {:error, %Ecto.Changeset{}} - - """ - def delete_category(%Category{} = category) do - Repo.delete(category) - end - - @doc """ - Returns an `%Ecto.Changeset{}` for tracking category changes. - - ## Examples - - iex> change_category(category) - %Ecto.Changeset{source: %Category{}} - - """ - def change_category(%Category{} = category) do - Category.changeset(category, %{}) - end - alias Mobilizon.Events.Tag @doc """ diff --git a/lib/mobilizon_web/resolvers/category.ex b/lib/mobilizon_web/resolvers/category.ex deleted file mode 100644 index d7d8997e8..000000000 --- a/lib/mobilizon_web/resolvers/category.ex +++ /dev/null @@ -1,48 +0,0 @@ -defmodule MobilizonWeb.Resolvers.Category do - @moduledoc """ - Handles the category-related GraphQL calls - """ - require Logger - alias Mobilizon.Actors.User - - ### - # TODO : Refactor this into MobilizonWeb.API.Categories when a standard AS category is defined - ### - def list_categories(_parent, %{page: page, limit: limit}, _resolution) do - categories = - Mobilizon.Events.list_categories(page, limit) - |> Enum.map(fn category -> - urls = MobilizonWeb.Uploaders.Category.urls({category.picture, category}) - Map.put(category, :picture, %{url: urls.original, url_thumbnail: urls.thumb}) - end) - - {:ok, categories} - end - - def create_category(_parent, %{title: title, picture: picture, description: description}, %{ - context: %{current_user: %User{} = _user} - }) do - with {:ok, category} <- - Mobilizon.Events.create_category(%{ - title: title, - description: description, - picture: picture - }), - urls <- MobilizonWeb.Uploaders.Category.urls({category.picture, category}) do - Logger.info("Created category " <> title) - {:ok, Map.put(category, :picture, %{url: urls.original, url_thumbnail: urls.thumb})} - else - {:error, %Ecto.Changeset{errors: errors} = _changeset} -> - # This is pretty ridiculous for changeset to error - errors = - Enum.into(errors, %{}) - |> Enum.map(fn {key, {value, _}} -> Atom.to_string(key) <> ": " <> value end) - - {:error, errors} - end - end - - def create_category(_parent, _args, %{}) do - {:error, "You are not allowed to create a category if not connected"} - end -end diff --git a/lib/mobilizon_web/schema.ex b/lib/mobilizon_web/schema.ex index b3d741eb7..7d6ff35ae 100644 --- a/lib/mobilizon_web/schema.ex +++ b/lib/mobilizon_web/schema.ex @@ -130,7 +130,6 @@ defmodule MobilizonWeb.Schema do import_fields(:group_queries) import_fields(:event_queries) import_fields(:participant_queries) - import_fields(:category_queries) import_fields(:tag_queries) end @@ -142,7 +141,6 @@ defmodule MobilizonWeb.Schema do import_fields(:person_mutations) import_fields(:group_mutations) import_fields(:event_mutations) - import_fields(:category_mutations) import_fields(:comment_mutations) import_fields(:participant_mutations) diff --git a/lib/mobilizon_web/schema/event.ex b/lib/mobilizon_web/schema/event.ex index 1214bf3a0..5747aeb50 100644 --- a/lib/mobilizon_web/schema/event.ex +++ b/lib/mobilizon_web/schema/event.ex @@ -7,7 +7,6 @@ defmodule MobilizonWeb.Schema.EventType do import Absinthe.Resolution.Helpers, only: [dataloader: 1] import_types(MobilizonWeb.Schema.AddressType) import_types(MobilizonWeb.Schema.Events.ParticipantType) - import_types(MobilizonWeb.Schema.Events.CategoryType) import_types(MobilizonWeb.Schema.TagType) alias MobilizonWeb.Resolvers @@ -44,7 +43,7 @@ defmodule MobilizonWeb.Schema.EventType do description: "The event's tags" ) - field(:category, :category, description: "The event's category") + field(:category, :string, description: "The event's category") field(:participants, list_of(:participant), resolve: &MobilizonWeb.Resolvers.Event.list_participants_for_event/3, diff --git a/lib/mobilizon_web/schema/events/category.ex b/lib/mobilizon_web/schema/events/category.ex deleted file mode 100644 index 521000ac7..000000000 --- a/lib/mobilizon_web/schema/events/category.ex +++ /dev/null @@ -1,34 +0,0 @@ -defmodule MobilizonWeb.Schema.Events.CategoryType do - @moduledoc """ - Schema representation for Category - """ - use Absinthe.Schema.Notation - alias MobilizonWeb.Resolvers - - @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 - - object :category_queries do - @desc "Get the list of categories" - field :categories, non_null(list_of(:category)) do - arg(:page, :integer, default_value: 1) - arg(:limit, :integer, default_value: 10) - resolve(&Resolvers.Category.list_categories/3) - end - end - - object :category_mutations do - @desc "Create a category with a title, description and picture" - field :create_category, type: :category do - arg(:title, non_null(:string)) - arg(:description, non_null(:string)) - arg(:picture, non_null(:upload)) - resolve(&Resolvers.Category.create_category/3) - end - end -end diff --git a/lib/mobilizon_web/uploaders/category.ex b/lib/mobilizon_web/uploaders/event.ex similarity index 91% rename from lib/mobilizon_web/uploaders/category.ex rename to lib/mobilizon_web/uploaders/event.ex index 247085f45..9f888e4a4 100644 --- a/lib/mobilizon_web/uploaders/category.ex +++ b/lib/mobilizon_web/uploaders/event.ex @@ -30,10 +30,9 @@ defmodule MobilizonWeb.Uploaders.Category do "#{title}_#{version}" end - # TODO : When we're sure creating a category is secured and made possible only for admins, use category name # Override the storage directory: def storage_dir(_, _) do - "uploads/categories/" + "uploads/event/" end # Provide a default URL if there hasn't been a file uploaded diff --git a/lib/mobilizon_web/views/activity_pub/object_view.ex b/lib/mobilizon_web/views/activity_pub/object_view.ex index d7b67055c..e8dcfa12a 100644 --- a/lib/mobilizon_web/views/activity_pub/object_view.ex +++ b/lib/mobilizon_web/views/activity_pub/object_view.ex @@ -1,6 +1,5 @@ defmodule MobilizonWeb.ActivityPub.ObjectView do use MobilizonWeb, :view - alias MobilizonWeb.ActivityPub.ObjectView alias Mobilizon.Service.ActivityPub.Utils def render("event.json", %{event: event}) do @@ -9,7 +8,7 @@ defmodule MobilizonWeb.ActivityPub.ObjectView do "actor" => event["actor"], "id" => event["id"], "name" => event["title"], - "category" => render_one(event["category"], ObjectView, "category.json", as: :category), + "category" => event["category"], "content" => event["summary"], "mediaType" => "text/html" # "published" => Timex.format!(event.inserted_at, "{ISO:Extended}"), @@ -35,15 +34,4 @@ defmodule MobilizonWeb.ActivityPub.ObjectView do Map.merge(comment, Utils.make_json_ld_header()) end - - def render("category.json", %{category: category}) when not is_nil(category) do - %{ - "identifier" => category.id, - "name" => category.title - } - end - - def render("category.json", %{category: _category}) do - nil - end end diff --git a/lib/service/activity_pub/activity_pub.ex b/lib/service/activity_pub/activity_pub.ex index 01f7c1d65..193806762 100644 --- a/lib/service/activity_pub/activity_pub.ex +++ b/lib/service/activity_pub/activity_pub.ex @@ -11,7 +11,7 @@ defmodule Mobilizon.Service.ActivityPub do """ alias Mobilizon.Events - alias Mobilizon.Events.{Event, Category, Comment} + alias Mobilizon.Events.{Event, Comment} alias Mobilizon.Service.ActivityPub.Transmogrifier alias Mobilizon.Service.WebFinger alias Mobilizon.Activity @@ -565,23 +565,8 @@ defmodule Mobilizon.Service.ActivityPub do # TODO : Use MobilizonWeb.API instead # TODO : refactor me and move me somewhere else! # TODO : also, there should be a form of cache that allows this to be more efficient - category = - if is_nil(ical_event.categories) do - nil - else - ical_category = ical_event.categories |> hd() |> String.downcase() - case ical_category |> Events.get_category_by_title() do - nil -> - case Events.create_category(%{"title" => ical_category}) do - {:ok, %Category{} = category} -> category - _ -> nil - end - - category -> - category - end - end + # ical_event.categories should be tags {:ok, event} = Events.create_event(%{ @@ -591,8 +576,7 @@ defmodule Mobilizon.Service.ActivityPub do updated_at: ical_event.stamp, description: ical_event.description |> sanitize_ical_event_strings, title: ical_event.summary |> sanitize_ical_event_strings, - organizer_actor: actor, - category: category + organizer_actor: actor }) event_to_activity(event, false) diff --git a/lib/service/activity_pub/utils.ex b/lib/service/activity_pub/utils.ex index 637b1c132..d00a49a93 100644 --- a/lib/service/activity_pub/utils.ex +++ b/lib/service/activity_pub/utils.ex @@ -117,7 +117,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do "description" => object["content"], "organizer_actor_id" => actor_id, "begins_on" => object["begins_on"], - "category_id" => Events.get_category_by_title(object["category"]).id, + "category" => object["category"], "url" => object["id"], "uuid" => object["uuid"] } diff --git a/mix.lock b/mix.lock index 8e9a80ecb..c065b8b12 100644 --- a/mix.lock +++ b/mix.lock @@ -71,7 +71,7 @@ "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_html": {:hex, :phoenix_html, "2.13.1", "fa8f034b5328e2dfa0e4131b5569379003f34bc1fafdaa84985b0b9d2f12e68b", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.0", "3bb31a9fbd40ffe8652e60c8660dffd72dd231efcdf49b744fb75b9ef7db5dd2", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"}, - "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [:mix], [], "hexpm"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"}, "plug": {:hex, :plug, "1.7.2", "d7b7db7fbd755e8283b6c0a50be71ec0a3d67d9213d74422d9372effc8e87fd1", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"}, "plug_cowboy": {:hex, :plug_cowboy, "2.0.1", "d798f8ee5acc86b7d42dbe4450b8b0dadf665ce588236eb0a751a132417a980e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, diff --git a/priv/repo/migrations/20190222151449_drop_categories.exs b/priv/repo/migrations/20190222151449_drop_categories.exs new file mode 100644 index 000000000..3211a4702 --- /dev/null +++ b/priv/repo/migrations/20190222151449_drop_categories.exs @@ -0,0 +1,35 @@ +defmodule Mobilizon.Repo.Migrations.DropCategories do + use Ecto.Migration + + def up do + # The category field is a string for the time being + # while we determine the definitive minimal list of + # categories in https://framagit.org/framasoft/mobilizon/issues/30 + # afterwards it will be a PostgreSQL enum and we'll + # just add new elements without being able to delete + # the previous ones + alter table(:events) do + add(:category, :string) + remove(:category_id) + end + + drop(table(:categories)) + end + + def down do + create table(:categories) do + add(:title, :string) + add(:description, :string) + add(:picture, :string) + + timestamps() + end + + create(unique_index(:categories, [:title])) + + alter table(:events) do + remove(:category) + add(:category_id, references(:categories, on_delete: :nothing)) + end + end +end diff --git a/test/mobilizon/events/events_test.exs b/test/mobilizon/events/events_test.exs index ddf92e29d..b07283994 100644 --- a/test/mobilizon/events/events_test.exs +++ b/test/mobilizon/events/events_test.exs @@ -11,7 +11,8 @@ defmodule Mobilizon.EventsTest do ends_on: "2010-04-17 14:00:00Z", title: "some title", url: "some url", - uuid: "b5126423-f1af-43e4-a923-002a03003ba4" + uuid: "b5126423-f1af-43e4-a923-002a03003ba4", + category: "meeting" } describe "events" do @@ -79,14 +80,12 @@ defmodule Mobilizon.EventsTest do test "create_event/1 with valid data creates a event" do actor = insert(:actor) - category = insert(:category) address = insert(:address) valid_attrs = @event_valid_attrs |> Map.put(:organizer_actor, actor) |> Map.put(:organizer_actor_id, actor.id) - |> Map.put(:category_id, category.id) |> Map.put(:address_id, address.id) with {:ok, %Event{} = event} <- Events.create_event(valid_attrs) do @@ -175,77 +174,6 @@ defmodule Mobilizon.EventsTest do end end - describe "categories" do - alias Mobilizon.Events.Category - - setup do - category = insert(:category) - {:ok, category: category} - end - - @valid_attrs %{ - description: "some description", - picture: %Plug.Upload{ - path: "test/fixtures/category_picture.png", - filename: "category_picture.png" - }, - title: "some title" - } - @update_attrs %{ - description: "some updated description", - picture: %Plug.Upload{ - path: "test/fixtures/category_picture_updated.png", - filename: "category_picture_updated.png" - }, - title: "some updated title" - } - @invalid_attrs %{description: nil, picture: nil, title: nil} - - test "list_categories/0 returns all categories", %{category: category} do - assert [category.id] == Events.list_categories() |> Enum.map(& &1.id) - end - - test "get_category!/1 returns the category with given id", %{category: category} do - assert Events.get_category!(category.id).id == category.id - end - - test "get_category_by_title/1 return the category with given title", %{category: category} do - assert Events.get_category_by_title(category.title).id == category.id - end - - test "create_category/1 with valid data creates a category" do - assert {:ok, %Category{} = category} = Events.create_category(@valid_attrs) - assert category.description == "some description" - assert category.picture.file_name == @valid_attrs.picture.filename - assert category.title == "some title" - end - - test "create_category/1 with invalid data returns error changeset" do - assert {:error, %Ecto.Changeset{}} = Events.create_category(@invalid_attrs) - end - - test "update_category/2 with valid data updates the category", %{category: category} do - assert {:ok, %Category{} = category} = Events.update_category(category, @update_attrs) - assert category.description == "some updated description" - assert category.picture.file_name == @update_attrs.picture.filename - assert category.title == "some updated title" - end - - test "update_category/2 with invalid data returns error changeset", %{category: category} do - assert {:error, %Ecto.Changeset{}} = Events.update_category(category, @invalid_attrs) - assert category.description == Events.get_category!(category.id).description - end - - test "delete_category/1 deletes the category", %{category: category} do - assert {:ok, %Category{}} = Events.delete_category(category) - assert_raise Ecto.NoResultsError, fn -> Events.get_category!(category.id) end - end - - test "change_category/1 returns a category changeset", %{category: category} do - assert %Ecto.Changeset{} = Events.change_category(category) - end - end - describe "tags" do alias Mobilizon.Events.Tag diff --git a/test/mobilizon_web/resolvers/category_resolver_test.exs b/test/mobilizon_web/resolvers/category_resolver_test.exs deleted file mode 100644 index bfc82b7a7..000000000 --- a/test/mobilizon_web/resolvers/category_resolver_test.exs +++ /dev/null @@ -1,77 +0,0 @@ -defmodule MobilizonWeb.Resolvers.CategoryResolverTest do - use MobilizonWeb.ConnCase - alias MobilizonWeb.AbsintheHelpers - import Mobilizon.Factory - - setup %{conn: conn} do - user = insert(:user) - actor = insert(:actor, user: user) - - {:ok, conn: conn, actor: actor, user: user} - end - - describe "Category Resolver" do - test "list_categories/3 returns the list of categories", context do - insert(:category) - insert(:category) - - query = """ - { - categories { - id, - title, - description, - picture { - url, - }, - } - } - """ - - res = - context.conn - |> get("/api", AbsintheHelpers.query_skeleton(query, "categories")) - - assert json_response(res, 200)["data"]["categories"] |> length == 2 - end - - # We can't test an upload…yet? - # test "create_category/3 creates a category", %{conn: conn, actor: actor, user: user} do - # mutation = """ - # mutation { - # createCategory(title: "my category", description: "my desc") { - # id, - # title, - # description, - # }, - # } - # """ - - # res = - # conn - # |> auth_conn(user) - # |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) - - # assert json_response(res, 200)["data"]["createCategory"]["title"] == "my category" - # end - - # test "create_category/3 doesn't create a category if the user isn't logged in", %{conn: conn, actor: actor} do - # mutation = """ - # mutation { - # createCategory(title: "my category", description: "my desc") { - # id, - # title, - # description, - # }, - # } - # """ - - # res = - # conn - # |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) - - # assert hd(json_response(res, 200)["errors"])["message"] == - # "You are not allowed to create a category if not connected" - # end - end -end diff --git a/test/mobilizon_web/resolvers/event_resolver_test.exs b/test/mobilizon_web/resolvers/event_resolver_test.exs index 8759086d0..636386364 100644 --- a/test/mobilizon_web/resolvers/event_resolver_test.exs +++ b/test/mobilizon_web/resolvers/event_resolver_test.exs @@ -9,7 +9,8 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do title: "some title", begins_on: DateTime.utc_now() |> DateTime.truncate(:second), uuid: "b5126423-f1af-43e4-a923-002a03003ba4", - url: "some url" + url: "some url", + category: "meeting" } setup %{conn: conn} do @@ -21,12 +22,9 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do describe "Event Resolver" do test "find_event/3 returns an event", context do - category = insert(:category) - event = @event |> Map.put(:organizer_actor_id, context.actor.id) - |> Map.put(:category_id, category.id) {:ok, event} = Events.create_event(event) @@ -61,8 +59,6 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do end test "create_event/3 creates an event", %{conn: conn, actor: actor, user: user} do - category = insert(:category) - mutation = """ mutation { createEvent( @@ -72,7 +68,7 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601() }", organizer_actor_id: "#{actor.id}", - category: "#{category.title}" + category: "birthday" ) { title, uuid diff --git a/test/mobilizon_web/resolvers/participant_resolver_test.exs b/test/mobilizon_web/resolvers/participant_resolver_test.exs index 070d6c0c1..bf526c8c2 100644 --- a/test/mobilizon_web/resolvers/participant_resolver_test.exs +++ b/test/mobilizon_web/resolvers/participant_resolver_test.exs @@ -9,7 +9,8 @@ defmodule MobilizonWeb.Resolvers.ParticipantResolverTest do title: "some title", begins_on: DateTime.utc_now() |> DateTime.truncate(:second), uuid: "b5126423-f1af-43e4-a923-002a03003ba4", - url: "some url" + url: "some url", + category: "meeting" } setup %{conn: conn} do @@ -313,13 +314,9 @@ defmodule MobilizonWeb.Resolvers.ParticipantResolverTest do end test "list_participants_for_event/3 returns participants for an event", context do - # Plain event - category = insert(:category) - event = @event |> Map.put(:organizer_actor_id, context.actor.id) - |> Map.put(:category_id, category.id) {:ok, event} = Events.create_event(event) diff --git a/test/support/factory.ex b/test/support/factory.ex index 33075e4d0..13281407e 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -53,13 +53,6 @@ defmodule Mobilizon.Factory do } end - def category_factory do - %Mobilizon.Events.Category{ - title: sequence("MyCategory"), - description: "My category desc" - } - end - def tag_factory do %Mobilizon.Events.Tag{ title: "MyTag", @@ -112,7 +105,7 @@ defmodule Mobilizon.Factory do begins_on: start, ends_on: Timex.shift(start, hours: 2), organizer_actor: actor, - category: build(:category), + category: sequence("something"), physical_address: build(:address), visibility: :public, url: "#{actor.url}/#{uuid}",