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: [
host: System.get_env("MOBILIZON_INSTANCE_HOST") || "mobilizon.local",
port: 80,
port: System.get_env("MOBILIZON_INSTANCE_PORT") || 4000,
scheme: "http"
],
debug_errors: true,

View File

@ -41,8 +41,12 @@ export default class PictureUpload extends Vue {
imageSrc: string | null = null;
mounted() {
this.updatePreview(this.pictureFile);
}
@Watch('pictureFile')
onPictureFileChanged (val: File) {
onPictureFileChanged(val: File) {
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`
query($uuid:UUID!) {
event(uuid: $uuid) {
@ -29,20 +66,14 @@ export const FETCH_EVENT = gql`
picture {
id
url
name
},
publishAt,
category,
# online_address,
# phone_address,
online_address,
phone_address,
physicalAddress {
description,
floor,
street,
locality,
postalCode,
region,
country,
geom
${physicalAddressQuery}
}
organizerActor {
avatar {
@ -65,9 +96,7 @@ export const FETCH_EVENT = gql`
${participantQuery}
},
tags {
id,
slug,
title
${tagsQuery}
},
relatedEvents {
uuid,
@ -86,23 +115,7 @@ export const FETCH_EVENT = gql`
}
},
options {
maximumAttendeeCapacity,
remainingAttendeeCapacity,
showRemainingAttendeeCapacity,
offers {
price,
priceCurrency,
url
},
participationConditions {
title,
content,
url
},
attendees,
program,
commentModeration,
showParticipationPrice
${optionsQuery}
}
}
}
@ -159,37 +172,62 @@ export const FETCH_EVENTS = gql`
`;
export const CREATE_EVENT = gql`
mutation CreateEvent(
mutation createEvent(
$organizerActorId: ID!,
$title: String!,
$description: String!,
$organizerActorId: ID!,
$category: String,
$beginsOn: DateTime!,
$endsOn: DateTime,
$picture: PictureInput,
$tags: [String],
$options: EventOptionsInput,
$physicalAddress: AddressInput,
$status: EventStatus,
$visibility: EventVisibility
$tags: [String],
$picture: PictureInput,
$onlineAddress: String,
$phoneAddress: String,
$category: String,
$physicalAddress: AddressInput,
$options: EventOptionsInput,
) {
createEvent(
organizerActorId: $organizerActorId,
title: $title,
description: $description,
beginsOn: $beginsOn,
endsOn: $endsOn,
organizerActorId: $organizerActorId,
category: $category,
options: $options,
picture: $picture,
status: $status,
visibility: $visibility,
tags: $tags,
physicalAddress: $physicalAddress,
visibility: $visibility
picture: $picture,
onlineAddress: $onlineAddress,
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}
}
}
}
@ -197,32 +235,62 @@ export const CREATE_EVENT = gql`
export const EDIT_EVENT = gql`
mutation updateEvent(
$id: ID!,
$title: String!,
$description: String!,
$organizerActorId: ID!,
$category: String,
$beginsOn: DateTime!,
$endsOn: DateTime,
$picture: PictureInput,
$tags: [String],
$options: EventOptionsInput,
$physicalAddress: AddressInput,
$visibility: EventVisibility
$id: ID!,
$title: String,
$description: String,
$beginsOn: DateTime,
$endsOn: DateTime,
$status: Int,
$visibility: EventVisibility
$tags: [String],
$picture: PictureInput,
$onlineAddress: String,
$phoneAddress: String,
$category: String,
$physicalAddress: AddressInput,
$options: EventOptionsInput,
) {
updateEvent(eventId: $id,
title: $title,
description: $description,
beginsOn: $beginsOn,
endsOn: $endsOn,
organizerActorId: $organizerActorId,
category: $category,
options: $options,
picture: $picture,
tags: $tags,
physicalAddress: $physicalAddress,
visibility: $visibility) {
uuid
updateEvent(
eventId: $id,
title: $title,
description: $description,
beginsOn: $beginsOn,
endsOn: $endsOn,
status: $status,
visibility: $visibility,
tags: $tags,
picture: $picture,
onlineAddress: $onlineAddress,
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 {
maximumAttendeeCapacity: number = 0;
remainingAttendeeCapacity: number = 0;
showRemainingAttendeeCapacity: boolean = false;
maximumAttendeeCapacity = 0;
remainingAttendeeCapacity = 0;
showRemainingAttendeeCapacity = false;
offers: IOffer[] = [];
participationConditions: IParticipationCondition[] = [];
attendees: string[] = [];
program: string = '';
commentModeration: CommentModeration = CommentModeration.ALLOW_ALL;
showParticipationPrice: boolean = false;
program = '';
commentModeration = CommentModeration.ALLOW_ALL;
showParticipationPrice = false;
}
export class EventModel implements IEvent {
@ -200,6 +200,25 @@ export class EventModel implements IEvent {
this.physicalAddress = hash.physicalAddress;
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>
</template>
<style lang="scss">
@import "@/variables.scss";
h2.subtitle {
margin: 10px 0;
span {
padding: 5px 7px;
display: inline;
background: $secondary;
}
}
</style>
<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 { 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 { IPerson, Person } from '@/types/actor';
import PictureUpload from '@/components/PictureUpload.vue';
@ -291,12 +305,7 @@ export default class EditEvent extends Vue {
* Build variables for Event GraphQL creation query
*/
private buildVariables() {
const obj = {
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);
const res = Object.assign(this.event.toEditJSON(), { organizerActorId: this.loggedPerson.id });
delete this.event.options['__typename'];
@ -360,16 +369,4 @@ export default class EditEvent extends Vue {
// }
}
</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(uploadLink);
const cache = new InMemoryCache({ fragmentMatcher });
const cache = new InMemoryCache({
fragmentMatcher,
});
const apolloClient = new ApolloClient({
cache,

View File

@ -135,7 +135,7 @@ defmodule MobilizonWeb.API.Utils do
end
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} <-
make_content_html(
content,

View File

@ -196,9 +196,9 @@ defmodule MobilizonWeb.Resolvers.Event do
# See https://github.com/absinthe-graphql/absinthe/issues/490
with args <- Map.put(args, :options, args[:options] || %{}),
{: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),
{:ok, args_with_organizer} <- save_attached_picture(args_with_organizer),
{:ok, args_with_organizer} <- save_physical_address(args_with_organizer),
{
:ok,
%Activity{
@ -236,9 +236,9 @@ defmodule MobilizonWeb.Resolvers.Event do
with args <- Map.put(args, :options, args[:options] || %{}),
{:ok, %Event{} = event} <- Mobilizon.Events.get_event_full(event_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_physical_address(args),
args <- Map.put(args, :organizer_actor, organizer_actor),
{
:ok,
%Activity{
@ -274,7 +274,7 @@ defmodule MobilizonWeb.Resolvers.Event do
}
} = args
) 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
# 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
@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),
args <- Map.put(args, :physical_address, address.url) do
{:ok, args}

View File

@ -36,8 +36,8 @@ defmodule MobilizonWeb.Schema.EventType do
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(:online_address, :string, description: "Online address of the event")
field(:phone_address, :string, description: "Phone address for the event")
field(:organizer_actor, :actor,
resolve: dataloader(Actors),
@ -208,9 +208,7 @@ defmodule MobilizonWeb.Schema.EventType do
arg(:description, non_null(:string))
arg(:begins_on, non_null(:datetime))
arg(:ends_on, :datetime)
arg(:state, :integer)
arg(:status, :integer)
arg(:public, :boolean)
arg(:status, :event_status)
arg(:visibility, :event_visibility, default_value: :private)
arg(:tags, list_of(:string),
@ -242,11 +240,8 @@ defmodule MobilizonWeb.Schema.EventType do
arg(:description, :string)
arg(:begins_on, :datetime)
arg(:ends_on, :datetime)
arg(:state, :integer)
arg(:status, :integer)
arg(:public, :boolean)
arg(:status, :event_status)
arg(:visibility, :event_visibility)
arg(:organizer_actor_id, :id)
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"
)
arg(:publish_at, :datetime)
arg(:online_address, :string)
arg(:phone_address, :string)
arg(:category, :string)

View File

@ -1,5 +1,5 @@
# 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 {
query: RootQueryType
@ -243,7 +243,7 @@ type Event {
local: Boolean
"""Online address of the event"""
onlineAddress: OnlineAddress
onlineAddress: String
"""The event options"""
options: EventOptions
@ -255,7 +255,7 @@ type Event {
participants: [Participant]
"""Phone address for the event"""
phoneAddress: PhoneAddress
phoneAddress: String
"""The type of the event's address"""
physicalAddress: Address
@ -591,11 +591,6 @@ type Member {
role: Int
}
type OnlineAddress {
info: String
url: String
}
"""
Describes how an actor is opened to follows
@ -704,11 +699,6 @@ type Persons {
total: Int!
}
type PhoneAddress {
info: String
phone: String
}
"""A picture"""
type Picture {
"""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
"""
picture: PictureInput
public: Boolean
publishAt: DateTime
state: Int
status: Int
"""The list of tags associated to the event"""
@ -976,7 +964,6 @@ type RootMutationType {
eventId: ID!
onlineAddress: String
options: EventOptionsInput
organizerActorId: ID
phoneAddress: String
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
"""
picture: PictureInput
public: Boolean
publishAt: DateTime
state: Int
status: Int
status: EventStatus
"""The list of tags associated to the event"""
tags: [String]

View File

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