Merge branch 'feature/edit-event2' into 'master'

Edit events fixes and update cache

See merge request framasoft/mobilizon!180
This commit is contained in:
Thomas Citharel 2019-09-09 20:25:15 +02:00
commit 5306e55099
11 changed files with 202 additions and 136 deletions

View file

@ -12,7 +12,7 @@ config :mobilizon, MobilizonWeb.Endpoint,
], ],
url: [ url: [
host: System.get_env("MOBILIZON_INSTANCE_HOST") || "mobilizon.local", host: System.get_env("MOBILIZON_INSTANCE_HOST") || "mobilizon.local",
port: 80, port: System.get_env("MOBILIZON_INSTANCE_PORT") || 4000,
scheme: "http" scheme: "http"
], ],
debug_errors: true, debug_errors: true,

View file

@ -41,8 +41,12 @@ export default class PictureUpload extends Vue {
imageSrc: string | null = null; imageSrc: string | null = null;
mounted() {
this.updatePreview(this.pictureFile);
}
@Watch('pictureFile') @Watch('pictureFile')
onPictureFileChanged (val: File) { onPictureFileChanged(val: File) {
this.updatePreview(val); this.updatePreview(val);
} }

View file

@ -12,6 +12,43 @@ const participantQuery = `
} }
`; `;
const physicalAddressQuery = `
description,
floor,
street,
locality,
postalCode,
region,
country,
geom
`;
const tagsQuery = `
id,
slug,
title
`;
const optionsQuery = `
maximumAttendeeCapacity,
remainingAttendeeCapacity,
showRemainingAttendeeCapacity,
offers {
price,
priceCurrency,
url
},
participationConditions {
title,
content,
url
},
attendees,
program,
commentModeration,
showParticipationPrice
`;
export const FETCH_EVENT = gql` export const FETCH_EVENT = gql`
query($uuid:UUID!) { query($uuid:UUID!) {
event(uuid: $uuid) { event(uuid: $uuid) {
@ -29,20 +66,14 @@ export const FETCH_EVENT = gql`
picture { picture {
id id
url url
name
}, },
publishAt, publishAt,
category, category,
# online_address, online_address,
# phone_address, phone_address,
physicalAddress { physicalAddress {
description, ${physicalAddressQuery}
floor,
street,
locality,
postalCode,
region,
country,
geom
} }
organizerActor { organizerActor {
avatar { avatar {
@ -65,9 +96,7 @@ export const FETCH_EVENT = gql`
${participantQuery} ${participantQuery}
}, },
tags { tags {
id, ${tagsQuery}
slug,
title
}, },
relatedEvents { relatedEvents {
uuid, uuid,
@ -86,23 +115,7 @@ export const FETCH_EVENT = gql`
} }
}, },
options { options {
maximumAttendeeCapacity, ${optionsQuery}
remainingAttendeeCapacity,
showRemainingAttendeeCapacity,
offers {
price,
priceCurrency,
url
},
participationConditions {
title,
content,
url
},
attendees,
program,
commentModeration,
showParticipationPrice
} }
} }
} }
@ -159,37 +172,62 @@ export const FETCH_EVENTS = gql`
`; `;
export const CREATE_EVENT = gql` export const CREATE_EVENT = gql`
mutation CreateEvent( mutation createEvent(
$organizerActorId: ID!,
$title: String!, $title: String!,
$description: String!, $description: String!,
$organizerActorId: ID!,
$category: String,
$beginsOn: DateTime!, $beginsOn: DateTime!,
$endsOn: DateTime, $endsOn: DateTime,
$picture: PictureInput, $status: EventStatus,
$tags: [String],
$options: EventOptionsInput,
$physicalAddress: AddressInput,
$visibility: EventVisibility $visibility: EventVisibility
$tags: [String],
$picture: PictureInput,
$onlineAddress: String,
$phoneAddress: String,
$category: String,
$physicalAddress: AddressInput,
$options: EventOptionsInput,
) { ) {
createEvent( createEvent(
organizerActorId: $organizerActorId,
title: $title, title: $title,
description: $description, description: $description,
beginsOn: $beginsOn, beginsOn: $beginsOn,
endsOn: $endsOn, endsOn: $endsOn,
organizerActorId: $organizerActorId, status: $status,
category: $category, visibility: $visibility,
options: $options,
picture: $picture,
tags: $tags, tags: $tags,
physicalAddress: $physicalAddress, picture: $picture,
visibility: $visibility onlineAddress: $onlineAddress,
phoneAddress: $phoneAddress,
category: $category,
physicalAddress: $physicalAddress
options: $options,
) { ) {
id, id,
uuid, uuid,
title, title,
description,
beginsOn,
endsOn,
status,
visibility,
picture { picture {
id
url url
},
publishAt,
category,
online_address,
phone_address,
physicalAddress {
${physicalAddressQuery}
},
tags {
${tagsQuery}
},
options {
${optionsQuery}
} }
} }
} }
@ -198,31 +236,61 @@ export const CREATE_EVENT = gql`
export const EDIT_EVENT = gql` export const EDIT_EVENT = gql`
mutation updateEvent( mutation updateEvent(
$id: ID!, $id: ID!,
$title: String!, $title: String,
$description: String!, $description: String,
$organizerActorId: ID!, $beginsOn: DateTime,
$category: String,
$beginsOn: DateTime!,
$endsOn: DateTime, $endsOn: DateTime,
$picture: PictureInput, $status: Int,
$tags: [String],
$options: EventOptionsInput,
$physicalAddress: AddressInput,
$visibility: EventVisibility $visibility: EventVisibility
$tags: [String],
$picture: PictureInput,
$onlineAddress: String,
$phoneAddress: String,
$category: String,
$physicalAddress: AddressInput,
$options: EventOptionsInput,
) { ) {
updateEvent(eventId: $id, updateEvent(
eventId: $id,
title: $title, title: $title,
description: $description, description: $description,
beginsOn: $beginsOn, beginsOn: $beginsOn,
endsOn: $endsOn, endsOn: $endsOn,
organizerActorId: $organizerActorId, status: $status,
category: $category, visibility: $visibility,
options: $options,
picture: $picture,
tags: $tags, tags: $tags,
physicalAddress: $physicalAddress, picture: $picture,
visibility: $visibility) { onlineAddress: $onlineAddress,
uuid phoneAddress: $phoneAddress,
category: $category,
physicalAddress: $physicalAddress
options: $options,
) {
id,
uuid,
title,
description,
beginsOn,
endsOn,
status,
visibility,
picture {
id
url
},
publishAt,
category,
online_address,
phone_address,
physicalAddress {
${physicalAddressQuery}
},
tags {
${tagsQuery}
},
options {
${optionsQuery}
}
} }
} }
`; `;

View file

@ -117,15 +117,15 @@ export interface IEventOptions {
} }
export class EventOptions implements IEventOptions { export class EventOptions implements IEventOptions {
maximumAttendeeCapacity: number = 0; maximumAttendeeCapacity = 0;
remainingAttendeeCapacity: number = 0; remainingAttendeeCapacity = 0;
showRemainingAttendeeCapacity: boolean = false; showRemainingAttendeeCapacity = false;
offers: IOffer[] = []; offers: IOffer[] = [];
participationConditions: IParticipationCondition[] = []; participationConditions: IParticipationCondition[] = [];
attendees: string[] = []; attendees: string[] = [];
program: string = ''; program = '';
commentModeration: CommentModeration = CommentModeration.ALLOW_ALL; commentModeration = CommentModeration.ALLOW_ALL;
showParticipationPrice: boolean = false; showParticipationPrice = false;
} }
export class EventModel implements IEvent { export class EventModel implements IEvent {
@ -200,6 +200,25 @@ export class EventModel implements IEvent {
this.physicalAddress = hash.physicalAddress; this.physicalAddress = hash.physicalAddress;
this.tags = hash.tags; this.tags = hash.tags;
this.options = hash.options; if (hash.options) this.options = hash.options;
}
toEditJSON () {
return {
id: this.id,
title: this.title,
description: this.description,
beginsOn: this.beginsOn.toISOString(),
endsOn: this.endsOn ? this.endsOn.toISOString() : null,
status: this.status,
visibility: this.visibility,
tags: this.tags.map(t => t.title),
picture: this.picture,
onlineAddress: this.onlineAddress,
phoneAddress: this.phoneAddress,
category: this.category,
physicalAddress: this.physicalAddress,
options: this.options,
};
} }
} }

View file

@ -174,10 +174,24 @@
</section> </section>
</template> </template>
<style lang="scss">
@import "@/variables.scss";
h2.subtitle {
margin: 10px 0;
span {
padding: 5px 7px;
display: inline;
background: $secondary;
}
}
</style>
<script lang="ts"> <script lang="ts">
import { CREATE_EVENT, EDIT_EVENT, FETCH_EVENT } from '@/graphql/event'; import { CREATE_EVENT, EDIT_EVENT, FETCH_EVENT, FETCH_EVENTS } from '@/graphql/event';
import { Component, Prop, Vue, Watch } from 'vue-property-decorator'; import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { EventModel, EventStatus, EventVisibility, EventVisibilityJoinOptions, CommentModeration } from '@/types/event.model'; import { EventModel, EventStatus, EventVisibility, EventVisibilityJoinOptions, CommentModeration, IEvent } from '@/types/event.model';
import { LOGGED_PERSON } from '@/graphql/actor'; import { LOGGED_PERSON } from '@/graphql/actor';
import { IPerson, Person } from '@/types/actor'; import { IPerson, Person } from '@/types/actor';
import PictureUpload from '@/components/PictureUpload.vue'; import PictureUpload from '@/components/PictureUpload.vue';
@ -291,12 +305,7 @@ export default class EditEvent extends Vue {
* Build variables for Event GraphQL creation query * Build variables for Event GraphQL creation query
*/ */
private buildVariables() { private buildVariables() {
const obj = { const res = Object.assign(this.event.toEditJSON(), { organizerActorId: this.loggedPerson.id });
organizerActorId: this.loggedPerson.id,
beginsOn: this.event.beginsOn.toISOString(),
tags: this.event.tags.map((tag: ITag) => tag.title),
};
const res = Object.assign({}, this.event, obj);
delete this.event.options['__typename']; delete this.event.options['__typename'];
@ -360,16 +369,4 @@ export default class EditEvent extends Vue {
// } // }
} }
</script> </script>
<style lang="scss">
@import "@/variables.scss";
h2.subtitle {
margin: 10px 0;
span {
padding: 5px 7px;
display: inline;
background: $secondary;
}
}
</style>

View file

@ -99,7 +99,9 @@ const link = authMiddleware
.concat(errorLink) .concat(errorLink)
.concat(uploadLink); .concat(uploadLink);
const cache = new InMemoryCache({ fragmentMatcher }); const cache = new InMemoryCache({
fragmentMatcher,
});
const apolloClient = new ApolloClient({ const apolloClient = new ApolloClient({
cache, cache,

View file

@ -135,7 +135,7 @@ defmodule MobilizonWeb.API.Utils do
end end
def prepare_content(actor, content, visibility, tags, in_reply_to) do def prepare_content(actor, content, visibility, tags, in_reply_to) do
with content <- String.trim(content), with content <- String.trim(content || ""),
{content_html, mentions, tags} <- {content_html, mentions, tags} <-
make_content_html( make_content_html(
content, content,

View file

@ -196,9 +196,9 @@ defmodule MobilizonWeb.Resolvers.Event do
# See https://github.com/absinthe-graphql/absinthe/issues/490 # See https://github.com/absinthe-graphql/absinthe/issues/490
with args <- Map.put(args, :options, args[:options] || %{}), with args <- Map.put(args, :options, args[:options] || %{}),
{:is_owned, true, organizer_actor} <- User.owns_actor(user, organizer_actor_id), {:is_owned, true, organizer_actor} <- User.owns_actor(user, organizer_actor_id),
{:ok, args} <- save_attached_picture(args),
{:ok, args} <- save_physical_address(args),
args_with_organizer <- Map.put(args, :organizer_actor, organizer_actor), args_with_organizer <- Map.put(args, :organizer_actor, organizer_actor),
{:ok, args_with_organizer} <- save_attached_picture(args_with_organizer),
{:ok, args_with_organizer} <- save_physical_address(args_with_organizer),
{ {
:ok, :ok,
%Activity{ %Activity{
@ -236,9 +236,9 @@ defmodule MobilizonWeb.Resolvers.Event do
with args <- Map.put(args, :options, args[:options] || %{}), with args <- Map.put(args, :options, args[:options] || %{}),
{:ok, %Event{} = event} <- Mobilizon.Events.get_event_full(event_id), {:ok, %Event{} = event} <- Mobilizon.Events.get_event_full(event_id),
{:is_owned, true, organizer_actor} <- User.owns_actor(user, event.organizer_actor_id), {:is_owned, true, organizer_actor} <- User.owns_actor(user, event.organizer_actor_id),
args <- Map.put(args, :organizer_actor, organizer_actor),
{:ok, args} <- save_attached_picture(args), {:ok, args} <- save_attached_picture(args),
{:ok, args} <- save_physical_address(args), {:ok, args} <- save_physical_address(args),
args <- Map.put(args, :organizer_actor, organizer_actor),
{ {
:ok, :ok,
%Activity{ %Activity{
@ -274,7 +274,7 @@ defmodule MobilizonWeb.Resolvers.Event do
} }
} = args } = args
) do ) do
{:ok, Map.put(args, :picture, Map.put(all_pic, :actor_id, args.organizer_actor_id))} {:ok, Map.put(args, :picture, Map.put(all_pic, :actor_id, args.organizer_actor.id))}
end end
# Otherwise if we use a previously uploaded picture we need to fetch it from database # Otherwise if we use a previously uploaded picture we need to fetch it from database
@ -310,7 +310,7 @@ defmodule MobilizonWeb.Resolvers.Event do
end end
@spec save_physical_address(map()) :: {:ok, map()} @spec save_physical_address(map()) :: {:ok, map()}
defp save_physical_address(%{physical_address: address} = args) do defp save_physical_address(%{physical_address: address} = args) when address != nil do
with {:ok, %Address{} = address} <- Addresses.create_address(address), with {:ok, %Address{} = address} <- Addresses.create_address(address),
args <- Map.put(args, :physical_address, address.url) do args <- Map.put(args, :physical_address, address.url) do
{:ok, args} {:ok, args}

View file

@ -36,8 +36,8 @@ defmodule MobilizonWeb.Schema.EventType do
description: "The type of the event's address" description: "The type of the event's address"
) )
field(:online_address, :online_address, description: "Online address of the event") field(:online_address, :string, description: "Online address of the event")
field(:phone_address, :phone_address, description: "Phone address for the event") field(:phone_address, :string, description: "Phone address for the event")
field(:organizer_actor, :actor, field(:organizer_actor, :actor,
resolve: dataloader(Actors), resolve: dataloader(Actors),
@ -208,9 +208,7 @@ defmodule MobilizonWeb.Schema.EventType do
arg(:description, non_null(:string)) arg(:description, non_null(:string))
arg(:begins_on, non_null(:datetime)) arg(:begins_on, non_null(:datetime))
arg(:ends_on, :datetime) arg(:ends_on, :datetime)
arg(:state, :integer) arg(:status, :event_status)
arg(:status, :integer)
arg(:public, :boolean)
arg(:visibility, :event_visibility, default_value: :private) arg(:visibility, :event_visibility, default_value: :private)
arg(:tags, list_of(:string), arg(:tags, list_of(:string),
@ -242,11 +240,8 @@ defmodule MobilizonWeb.Schema.EventType do
arg(:description, :string) arg(:description, :string)
arg(:begins_on, :datetime) arg(:begins_on, :datetime)
arg(:ends_on, :datetime) arg(:ends_on, :datetime)
arg(:state, :integer) arg(:status, :event_status)
arg(:status, :integer)
arg(:public, :boolean)
arg(:visibility, :event_visibility) arg(:visibility, :event_visibility)
arg(:organizer_actor_id, :id)
arg(:tags, list_of(:string), description: "The list of tags associated to the event") arg(:tags, list_of(:string), description: "The list of tags associated to the event")
@ -255,7 +250,6 @@ defmodule MobilizonWeb.Schema.EventType do
"The picture for the event, either as an object or directly the ID of an existing Picture" "The picture for the event, either as an object or directly the ID of an existing Picture"
) )
arg(:publish_at, :datetime)
arg(:online_address, :string) arg(:online_address, :string)
arg(:phone_address, :string) arg(:phone_address, :string)
arg(:category, :string) arg(:category, :string)

View file

@ -1,5 +1,5 @@
# source: http://localhost:4000/api # source: http://localhost:4000/api
# timestamp: Thu Sep 05 2019 13:00:10 GMT+0200 (GMT+02:00) # timestamp: Mon Sep 09 2019 11:37:31 GMT+0200 (heure dété dEurope centrale)
schema { schema {
query: RootQueryType query: RootQueryType
@ -243,7 +243,7 @@ type Event {
local: Boolean local: Boolean
"""Online address of the event""" """Online address of the event"""
onlineAddress: OnlineAddress onlineAddress: String
"""The event options""" """The event options"""
options: EventOptions options: EventOptions
@ -255,7 +255,7 @@ type Event {
participants: [Participant] participants: [Participant]
"""Phone address for the event""" """Phone address for the event"""
phoneAddress: PhoneAddress phoneAddress: String
"""The type of the event's address""" """The type of the event's address"""
physicalAddress: Address physicalAddress: Address
@ -591,11 +591,6 @@ type Member {
role: Int role: Int
} }
type OnlineAddress {
info: String
url: String
}
""" """
Describes how an actor is opened to follows Describes how an actor is opened to follows
@ -704,11 +699,6 @@ type Persons {
total: Int! total: Int!
} }
type PhoneAddress {
info: String
phone: String
}
"""A picture""" """A picture"""
type Picture { type Picture {
"""The picture's alternative text""" """The picture's alternative text"""
@ -836,9 +826,7 @@ type RootMutationType {
The picture for the event, either as an object or directly the ID of an existing Picture The picture for the event, either as an object or directly the ID of an existing Picture
""" """
picture: PictureInput picture: PictureInput
public: Boolean
publishAt: DateTime publishAt: DateTime
state: Int
status: Int status: Int
"""The list of tags associated to the event""" """The list of tags associated to the event"""
@ -976,7 +964,6 @@ type RootMutationType {
eventId: ID! eventId: ID!
onlineAddress: String onlineAddress: String
options: EventOptionsInput options: EventOptionsInput
organizerActorId: ID
phoneAddress: String phoneAddress: String
physicalAddress: AddressInput physicalAddress: AddressInput
@ -984,10 +971,7 @@ type RootMutationType {
The picture for the event, either as an object or directly the ID of an existing Picture The picture for the event, either as an object or directly the ID of an existing Picture
""" """
picture: PictureInput picture: PictureInput
public: Boolean status: EventStatus
publishAt: DateTime
state: Int
status: Int
"""The list of tags associated to the event""" """The list of tags associated to the event"""
tags: [String] tags: [String]

View file

@ -486,7 +486,6 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
description: "description updated", description: "description updated",
begins_on: "#{begins_on}", begins_on: "#{begins_on}",
event_id: #{event.id}, event_id: #{event.id},
organizer_actor_id: "#{actor.id}",
category: "birthday", category: "birthday",
tags: ["tag1_updated", "tag2_updated"] tags: ["tag1_updated", "tag2_updated"]
) { ) {
@ -533,7 +532,6 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
description: "description updated", description: "description updated",
begins_on: "#{begins_on}", begins_on: "#{begins_on}",
event_id: #{event.id}, event_id: #{event.id},
organizer_actor_id: "#{actor.id}",
category: "birthday", category: "birthday",
picture: { picture: {
picture: { picture: {