Add draft feature
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
c0c0659a5d
commit
174a844ed5
@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<h2 class="title" ref="title">{{ event.title }}</h2>
|
<h2 class="title" ref="title">{{ event.title }}</h2>
|
||||||
</div>
|
</div>
|
||||||
<span>
|
<span class="organizer-place-wrapper">
|
||||||
<span v-if="actorDisplayName && actorDisplayName !== '@'">{{ $t('By {name}', { name: actorDisplayName }) }}</span>
|
<span v-if="actorDisplayName && actorDisplayName !== '@'">{{ $t('By {name}', { name: actorDisplayName }) }}</span>
|
||||||
<span v-if="event.physicalAddress && (event.physicalAddress.locality || event.physicalAddress.description)">
|
<span v-if="event.physicalAddress && (event.physicalAddress.locality || event.physicalAddress.description)">
|
||||||
- {{ event.physicalAddress.locality || event.physicalAddress.description }}
|
- {{ event.physicalAddress.locality || event.physicalAddress.description }}
|
||||||
@ -142,6 +142,17 @@ export default class EventCard extends Vue {
|
|||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
font-size: 1.6em;
|
font-size: 1.6em;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span.organizer-place-wrapper {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
span:last-child {
|
||||||
|
flex: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ export const UPDATE_CURRENT_ACTOR_CLIENT = gql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const LOGGED_USER_PARTICIPATIONS = gql`
|
export const LOGGED_USER_PARTICIPATIONS = gql`
|
||||||
query LoggedUserParticipations($afterDateTime: DateTime, $beforeDateTime: DateTime $page: Int, $limit: Int) {
|
query LoggedUserParticipations($afterDateTime: DateTime, $beforeDateTime: DateTime, $page: Int, $limit: Int) {
|
||||||
loggedUser {
|
loggedUser {
|
||||||
participations(afterDatetime: $afterDateTime, beforeDatetime: $beforeDateTime, page: $page, limit: $limit) {
|
participations(afterDatetime: $afterDateTime, beforeDatetime: $beforeDateTime, page: $page, limit: $limit) {
|
||||||
event {
|
event {
|
||||||
@ -106,6 +106,40 @@ query LoggedUserParticipations($afterDateTime: DateTime, $beforeDateTime: DateTi
|
|||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
export const LOGGED_USER_DRAFTS = gql`
|
||||||
|
query LoggedUserDrafts($page: Int, $limit: Int) {
|
||||||
|
loggedUser {
|
||||||
|
drafts(page: $page, limit: $limit) {
|
||||||
|
id,
|
||||||
|
uuid,
|
||||||
|
title,
|
||||||
|
picture {
|
||||||
|
url,
|
||||||
|
alt
|
||||||
|
},
|
||||||
|
beginsOn,
|
||||||
|
visibility,
|
||||||
|
organizerActor {
|
||||||
|
id,
|
||||||
|
preferredUsername,
|
||||||
|
name,
|
||||||
|
domain,
|
||||||
|
avatar {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
},
|
||||||
|
participantStats {
|
||||||
|
approved,
|
||||||
|
unapproved
|
||||||
|
},
|
||||||
|
options {
|
||||||
|
maximumAttendeeCapacity
|
||||||
|
remainingAttendeeCapacity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
|
||||||
export const IDENTITIES = gql`
|
export const IDENTITIES = gql`
|
||||||
query {
|
query {
|
||||||
identities {
|
identities {
|
||||||
|
@ -69,6 +69,7 @@ export const FETCH_EVENT = gql`
|
|||||||
status,
|
status,
|
||||||
visibility,
|
visibility,
|
||||||
joinOptions,
|
joinOptions,
|
||||||
|
draft,
|
||||||
picture {
|
picture {
|
||||||
id
|
id
|
||||||
url
|
url
|
||||||
@ -190,6 +191,7 @@ export const CREATE_EVENT = gql`
|
|||||||
$status: EventStatus,
|
$status: EventStatus,
|
||||||
$visibility: EventVisibility,
|
$visibility: EventVisibility,
|
||||||
$joinOptions: EventJoinOptions,
|
$joinOptions: EventJoinOptions,
|
||||||
|
$draft: Boolean,
|
||||||
$tags: [String],
|
$tags: [String],
|
||||||
$picture: PictureInput,
|
$picture: PictureInput,
|
||||||
$onlineAddress: String,
|
$onlineAddress: String,
|
||||||
@ -207,6 +209,7 @@ export const CREATE_EVENT = gql`
|
|||||||
status: $status,
|
status: $status,
|
||||||
visibility: $visibility,
|
visibility: $visibility,
|
||||||
joinOptions: $joinOptions,
|
joinOptions: $joinOptions,
|
||||||
|
draft: $draft,
|
||||||
tags: $tags,
|
tags: $tags,
|
||||||
picture: $picture,
|
picture: $picture,
|
||||||
onlineAddress: $onlineAddress,
|
onlineAddress: $onlineAddress,
|
||||||
@ -224,6 +227,7 @@ export const CREATE_EVENT = gql`
|
|||||||
status,
|
status,
|
||||||
visibility,
|
visibility,
|
||||||
joinOptions,
|
joinOptions,
|
||||||
|
draft,
|
||||||
picture {
|
picture {
|
||||||
id
|
id
|
||||||
url
|
url
|
||||||
@ -255,6 +259,7 @@ export const EDIT_EVENT = gql`
|
|||||||
$status: EventStatus,
|
$status: EventStatus,
|
||||||
$visibility: EventVisibility,
|
$visibility: EventVisibility,
|
||||||
$joinOptions: EventJoinOptions,
|
$joinOptions: EventJoinOptions,
|
||||||
|
$draft: Boolean,
|
||||||
$tags: [String],
|
$tags: [String],
|
||||||
$picture: PictureInput,
|
$picture: PictureInput,
|
||||||
$onlineAddress: String,
|
$onlineAddress: String,
|
||||||
@ -272,6 +277,7 @@ export const EDIT_EVENT = gql`
|
|||||||
status: $status,
|
status: $status,
|
||||||
visibility: $visibility,
|
visibility: $visibility,
|
||||||
joinOptions: $joinOptions,
|
joinOptions: $joinOptions,
|
||||||
|
draft: $draft,
|
||||||
tags: $tags,
|
tags: $tags,
|
||||||
picture: $picture,
|
picture: $picture,
|
||||||
onlineAddress: $onlineAddress,
|
onlineAddress: $onlineAddress,
|
||||||
@ -289,6 +295,7 @@ export const EDIT_EVENT = gql`
|
|||||||
status,
|
status,
|
||||||
visibility,
|
visibility,
|
||||||
joinOptions,
|
joinOptions,
|
||||||
|
draft,
|
||||||
picture {
|
picture {
|
||||||
id
|
id
|
||||||
url
|
url
|
||||||
|
@ -13,10 +13,14 @@
|
|||||||
"Allow all comments": "Allow all comments",
|
"Allow all comments": "Allow all comments",
|
||||||
"Approve": "Approve",
|
"Approve": "Approve",
|
||||||
"Are you going to this event?": "Are you going to this event?",
|
"Are you going to this event?": "Are you going to this event?",
|
||||||
|
"Are you sure you want to cancel the event creation? You'll lose all modifications.": "Are you sure you want to cancel the event creation? You'll lose all modifications.",
|
||||||
|
"Are you sure you want to cancel the event edition? You'll lose all modifications.": "Are you sure you want to cancel the event edition? You'll lose all modifications.",
|
||||||
"Are you sure you want to cancel your participation at event \"{title}\"?": "Are you sure you want to cancel your participation at event \"{title}\"?",
|
"Are you sure you want to cancel your participation at event \"{title}\"?": "Are you sure you want to cancel your participation at event \"{title}\"?",
|
||||||
"Are you sure you want to delete this event? This action cannot be reverted.": "Are you sure you want to delete this event? This action cannot be reverted.",
|
"Are you sure you want to delete this event? This action cannot be reverted.": "Are you sure you want to delete this event? This action cannot be reverted.",
|
||||||
"Before you can login, you need to click on the link inside it to validate your account": "Before you can login, you need to click on the link inside it to validate your account",
|
"Before you can login, you need to click on the link inside it to validate your account": "Before you can login, you need to click on the link inside it to validate your account",
|
||||||
"By {name}": "By {name}",
|
"By {name}": "By {name}",
|
||||||
|
"Cancel creation": "Cancel creation",
|
||||||
|
"Cancel edition": "Cancel edition",
|
||||||
"Cancel my participation request…": "Cancel my participation request…",
|
"Cancel my participation request…": "Cancel my participation request…",
|
||||||
"Cancel my participation…": "Cancel my participation…",
|
"Cancel my participation…": "Cancel my participation…",
|
||||||
"Cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
@ -33,6 +37,7 @@
|
|||||||
"Comments": "Comments",
|
"Comments": "Comments",
|
||||||
"Confirm my particpation": "Confirm my particpation",
|
"Confirm my particpation": "Confirm my particpation",
|
||||||
"Confirmed: Will happen": "Confirmed: Will happen",
|
"Confirmed: Will happen": "Confirmed: Will happen",
|
||||||
|
"Continue editing": "Continue editing",
|
||||||
"Country": "Country",
|
"Country": "Country",
|
||||||
"Create a new event": "Create a new event",
|
"Create a new event": "Create a new event",
|
||||||
"Create a new group": "Create a new group",
|
"Create a new group": "Create a new group",
|
||||||
@ -59,12 +64,15 @@
|
|||||||
"Display participation price": "Display participation price",
|
"Display participation price": "Display participation price",
|
||||||
"Displayed name": "Displayed name",
|
"Displayed name": "Displayed name",
|
||||||
"Do you want to participate in {title}?": "Do you want to participate in {title}?",
|
"Do you want to participate in {title}?": "Do you want to participate in {title}?",
|
||||||
|
"Draft": "Draft",
|
||||||
|
"Drafts": "Drafts",
|
||||||
"Edit": "Edit",
|
"Edit": "Edit",
|
||||||
"Either the account is already validated, either the validation token is incorrect.": "Either the account is already validated, either the validation token is incorrect.",
|
"Either the account is already validated, either the validation token is incorrect.": "Either the account is already validated, either the validation token is incorrect.",
|
||||||
"Email": "Email",
|
"Email": "Email",
|
||||||
"Ends on…": "Ends on…",
|
"Ends on…": "Ends on…",
|
||||||
"Enter some tags": "Enter some tags",
|
"Enter some tags": "Enter some tags",
|
||||||
"Error while validating account": "Error while validating account",
|
"Error while validating account": "Error while validating account",
|
||||||
|
"Event already passed": "Event already passed",
|
||||||
"Event list": "Event list",
|
"Event list": "Event list",
|
||||||
"Event {eventTitle} deleted": "Event {eventTitle} deleted",
|
"Event {eventTitle} deleted": "Event {eventTitle} deleted",
|
||||||
"Event {eventTitle} reported": "Event {eventTitle} reported",
|
"Event {eventTitle} reported": "Event {eventTitle} reported",
|
||||||
@ -165,6 +173,7 @@
|
|||||||
"Public event": "Public event",
|
"Public event": "Public event",
|
||||||
"Public feeds": "Public feeds",
|
"Public feeds": "Public feeds",
|
||||||
"Public iCal Feed": "Public iCal Feed",
|
"Public iCal Feed": "Public iCal Feed",
|
||||||
|
"Publish": "Publish",
|
||||||
"Published events": "Published events",
|
"Published events": "Published events",
|
||||||
"RSS/Atom Feed": "RSS/Atom Feed",
|
"RSS/Atom Feed": "RSS/Atom Feed",
|
||||||
"Region": "Region",
|
"Region": "Region",
|
||||||
@ -172,10 +181,14 @@
|
|||||||
"Register": "Register",
|
"Register": "Register",
|
||||||
"Registration is currently closed.": "Registration is currently closed.",
|
"Registration is currently closed.": "Registration is currently closed.",
|
||||||
"Reject": "Reject",
|
"Reject": "Reject",
|
||||||
|
"Rejected participations": "Rejected participations",
|
||||||
|
"Rejected": "Rejected",
|
||||||
"Report this event": "Report this event",
|
"Report this event": "Report this event",
|
||||||
"Report": "Report",
|
"Report": "Report",
|
||||||
|
"Requests": "Requests",
|
||||||
"Resend confirmation email": "Resend confirmation email",
|
"Resend confirmation email": "Resend confirmation email",
|
||||||
"Reset my password": "Reset my password",
|
"Reset my password": "Reset my password",
|
||||||
|
"Save draft": "Save draft",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Search events, groups, etc.": "Search events, groups, etc.",
|
"Search events, groups, etc.": "Search events, groups, etc.",
|
||||||
"Search results: \"{search}\"": "Search results: \"{search}\"",
|
"Search results: \"{search}\"": "Search results: \"{search}\"",
|
||||||
@ -210,7 +223,9 @@
|
|||||||
"To confirm, type your event title \"{eventTitle}\"": "To confirm, type your event title \"{eventTitle}\"",
|
"To confirm, type your event title \"{eventTitle}\"": "To confirm, type your event title \"{eventTitle}\"",
|
||||||
"To confirm, type your identity username \"{preferredUsername}\"": "To confirm, type your identity username \"{preferredUsername}\"",
|
"To confirm, type your identity username \"{preferredUsername}\"": "To confirm, type your identity username \"{preferredUsername}\"",
|
||||||
"Transfer to {outsideDomain}": "Transfer to {outsideDomain}",
|
"Transfer to {outsideDomain}": "Transfer to {outsideDomain}",
|
||||||
|
"Unfortunately, your participation request was rejected by the organizers.": "Unfortunately, your participation request was rejected by the organizers.",
|
||||||
"Unknown error.": "Unknown error.",
|
"Unknown error.": "Unknown error.",
|
||||||
|
"Unsaved changes": "Unsaved changes",
|
||||||
"Upcoming": "Upcoming",
|
"Upcoming": "Upcoming",
|
||||||
"Update event {name}": "Update event {name}",
|
"Update event {name}": "Update event {name}",
|
||||||
"Update my event": "Update my event",
|
"Update my event": "Update my event",
|
||||||
@ -253,9 +268,5 @@
|
|||||||
"{approved} / {total} seats": "{approved} / {total} seats",
|
"{approved} / {total} seats": "{approved} / {total} seats",
|
||||||
"{count} participants": "{count} participants",
|
"{count} participants": "{count} participants",
|
||||||
"{count} requests waiting": "{count} requests waiting",
|
"{count} requests waiting": "{count} requests waiting",
|
||||||
"© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks": "© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks",
|
"© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks": "© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks"
|
||||||
"Requests": "Requests",
|
|
||||||
"Rejected": "Rejected",
|
|
||||||
"Rejected participations": "Rejected participations",
|
|
||||||
"Unfortunately, your participation request was rejected by the organizers.": "Unfortunately, your participation request was rejected by the organizers."
|
|
||||||
}
|
}
|
@ -13,10 +13,14 @@
|
|||||||
"Allow all comments": "Autoriser tous les commentaires",
|
"Allow all comments": "Autoriser tous les commentaires",
|
||||||
"Approve": "Approuver",
|
"Approve": "Approuver",
|
||||||
"Are you going to this event?": "Allez-vous à cet événement ?",
|
"Are you going to this event?": "Allez-vous à cet événement ?",
|
||||||
|
"Are you sure you want to cancel the event creation? You'll lose all modifications.": "Étes-vous certain⋅e de vouloir annuler la création de l'événement ? Vous allez perdre toutes vos modifications.",
|
||||||
|
"Are you sure you want to cancel the event edition? You'll lose all modifications.": "Étes-vous certain⋅e de vouloir annuler l'édition de l'événement ? Vous allez perdre toutes vos modifications.",
|
||||||
"Are you sure you want to cancel your participation at event \"{title}\"?": "Êtes-vous certain⋅e de vouloir annuler votre participation à l'événement « {title} » ?",
|
"Are you sure you want to cancel your participation at event \"{title}\"?": "Êtes-vous certain⋅e de vouloir annuler votre participation à l'événement « {title} » ?",
|
||||||
"Are you sure you want to delete this event? This action cannot be reverted.": "Êtes-vous certain⋅e de vouloir supprimer cet événement ? Cette action ne peut être annulée.",
|
"Are you sure you want to delete this event? This action cannot be reverted.": "Êtes-vous certain⋅e de vouloir supprimer cet événement ? Cette action ne peut être annulée.",
|
||||||
"Before you can login, you need to click on the link inside it to validate your account": "Avant que vous puissiez vous enregistrer, vous devez cliquer sur le lien à l'intérieur pour valider votre compte",
|
"Before you can login, you need to click on the link inside it to validate your account": "Avant que vous puissiez vous enregistrer, vous devez cliquer sur le lien à l'intérieur pour valider votre compte",
|
||||||
"By {name}": "Par {name}",
|
"By {name}": "Par {name}",
|
||||||
|
"Cancel creation": "Annuler la création",
|
||||||
|
"Cancel edition": "Annuler l'édition",
|
||||||
"Cancel my participation request…": "Cancel my participation request…",
|
"Cancel my participation request…": "Cancel my participation request…",
|
||||||
"Cancel my participation…": "Annuler ma participation…",
|
"Cancel my participation…": "Annuler ma participation…",
|
||||||
"Cancel": "Annuler",
|
"Cancel": "Annuler",
|
||||||
@ -33,6 +37,7 @@
|
|||||||
"Comments": "Commentaires",
|
"Comments": "Commentaires",
|
||||||
"Confirm my particpation": "Confirmer ma particpation",
|
"Confirm my particpation": "Confirmer ma particpation",
|
||||||
"Confirmed: Will happen": "Confirmé : aura lieu",
|
"Confirmed: Will happen": "Confirmé : aura lieu",
|
||||||
|
"Continue editing": "Continuer l'édition",
|
||||||
"Country": "Pays",
|
"Country": "Pays",
|
||||||
"Create a new event": "Créer un nouvel événement",
|
"Create a new event": "Créer un nouvel événement",
|
||||||
"Create a new group": "Créer un nouveau groupe",
|
"Create a new group": "Créer un nouveau groupe",
|
||||||
@ -59,12 +64,15 @@
|
|||||||
"Display participation price": "Afficher un prix de participation",
|
"Display participation price": "Afficher un prix de participation",
|
||||||
"Displayed name": "Nom affiché",
|
"Displayed name": "Nom affiché",
|
||||||
"Do you want to participate in {title}?": "Voulez-vous participer à {title} ?",
|
"Do you want to participate in {title}?": "Voulez-vous participer à {title} ?",
|
||||||
|
"Draft": "Brouillon",
|
||||||
|
"Drafts": "Brouillons",
|
||||||
"Edit": "Éditer",
|
"Edit": "Éditer",
|
||||||
"Either the account is already validated, either the validation token is incorrect.": "Soit le compte est déjà validé, soit le jeton de validation est incorrect.",
|
"Either the account is already validated, either the validation token is incorrect.": "Soit le compte est déjà validé, soit le jeton de validation est incorrect.",
|
||||||
"Email": "Email",
|
"Email": "Email",
|
||||||
"Ends on…": "Se termine le…",
|
"Ends on…": "Se termine le…",
|
||||||
"Enter some tags": "Écrire des tags",
|
"Enter some tags": "Écrire des tags",
|
||||||
"Error while validating account": "Erreur lors de la validation du compte",
|
"Error while validating account": "Erreur lors de la validation du compte",
|
||||||
|
"Event already passed": "Événement déjà passé",
|
||||||
"Event list": "Liste d'événements",
|
"Event list": "Liste d'événements",
|
||||||
"Event {eventTitle} deleted": "Événement {eventTitle} supprimé",
|
"Event {eventTitle} deleted": "Événement {eventTitle} supprimé",
|
||||||
"Event {eventTitle} reported": "Événement {eventTitle} signalé",
|
"Event {eventTitle} reported": "Événement {eventTitle} signalé",
|
||||||
@ -165,6 +173,7 @@
|
|||||||
"Public event": "Événement public",
|
"Public event": "Événement public",
|
||||||
"Public feeds": "Flux publics",
|
"Public feeds": "Flux publics",
|
||||||
"Public iCal Feed": "Flux iCal public",
|
"Public iCal Feed": "Flux iCal public",
|
||||||
|
"Publish": "Publier",
|
||||||
"Published events": "Événements publiés",
|
"Published events": "Événements publiés",
|
||||||
"RSS/Atom Feed": "Flux RSS/Atom",
|
"RSS/Atom Feed": "Flux RSS/Atom",
|
||||||
"Region": "Région",
|
"Region": "Région",
|
||||||
@ -172,10 +181,14 @@
|
|||||||
"Register": "S'inscrire",
|
"Register": "S'inscrire",
|
||||||
"Registration is currently closed.": "Les inscriptions sont actuellement fermées.",
|
"Registration is currently closed.": "Les inscriptions sont actuellement fermées.",
|
||||||
"Reject": "Rejetter",
|
"Reject": "Rejetter",
|
||||||
|
"Rejected participations": "Participations rejetées",
|
||||||
|
"Rejected": "Rejetés",
|
||||||
"Report this event": "Signaler cet événement",
|
"Report this event": "Signaler cet événement",
|
||||||
"Report": "Signaler",
|
"Report": "Signaler",
|
||||||
|
"Requests": "Requêtes",
|
||||||
"Resend confirmation email": "Envoyer à nouveau l'email de confirmation",
|
"Resend confirmation email": "Envoyer à nouveau l'email de confirmation",
|
||||||
"Reset my password": "Réinitialiser mon mot de passe",
|
"Reset my password": "Réinitialiser mon mot de passe",
|
||||||
|
"Save draft": "Enregistrer le brouillon",
|
||||||
"Save": "Enregistrer",
|
"Save": "Enregistrer",
|
||||||
"Search events, groups, etc.": "Rechercher des événements, des groupes, etc.",
|
"Search events, groups, etc.": "Rechercher des événements, des groupes, etc.",
|
||||||
"Search results: \"{search}\"": "Résultats de recherche: « {search} »",
|
"Search results: \"{search}\"": "Résultats de recherche: « {search} »",
|
||||||
@ -210,7 +223,9 @@
|
|||||||
"To confirm, type your event title \"{eventTitle}\"": "Pour confirmer, entrez le titre de l'événement « {eventTitle} »",
|
"To confirm, type your event title \"{eventTitle}\"": "Pour confirmer, entrez le titre de l'événement « {eventTitle} »",
|
||||||
"To confirm, type your identity username \"{preferredUsername}\"": "Pour confirmer, entrez le nom de l’identité « {preferredUsername} »",
|
"To confirm, type your identity username \"{preferredUsername}\"": "Pour confirmer, entrez le nom de l’identité « {preferredUsername} »",
|
||||||
"Transfer to {outsideDomain}": "Transférer à {outsideDomain}",
|
"Transfer to {outsideDomain}": "Transférer à {outsideDomain}",
|
||||||
|
"Unfortunately, your participation request was rejected by the organizers.": "Malheureusement, votre demande de participation a été refusée par les organisateur⋅ices.",
|
||||||
"Unknown error.": "Erreur inconnue.",
|
"Unknown error.": "Erreur inconnue.",
|
||||||
|
"Unsaved changes": "Modifications non enregistrées",
|
||||||
"Upcoming": "À venir",
|
"Upcoming": "À venir",
|
||||||
"Update event {name}": "Éditer l'événement {name}",
|
"Update event {name}": "Éditer l'événement {name}",
|
||||||
"Update my event": "Éditer mon événement",
|
"Update my event": "Éditer mon événement",
|
||||||
@ -253,9 +268,5 @@
|
|||||||
"{approved} / {total} seats": "{approved} / {total} places",
|
"{approved} / {total} seats": "{approved} / {total} places",
|
||||||
"{count} participants": "Un⋅e participant⋅e|{count} participant⋅e⋅s",
|
"{count} participants": "Un⋅e participant⋅e|{count} participant⋅e⋅s",
|
||||||
"{count} requests waiting": "Un⋅e demande en attente|{count} demandes en attente",
|
"{count} requests waiting": "Un⋅e demande en attente|{count} demandes en attente",
|
||||||
"© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks": "© Les contributeurs de Mobilizon {date} - Fait avec Elixir, Phoenix, VueJS & et de l'amour et des semaines",
|
"© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks": "© Les contributeurs de Mobilizon {date} - Fait avec Elixir, Phoenix, VueJS & et de l'amour et des semaines"
|
||||||
"Requests": "Requêtes",
|
|
||||||
"Rejected": "Rejetés",
|
|
||||||
"Rejected participations": "Participations rejetées",
|
|
||||||
"Unfortunately, your participation request was rejected by the organizers.": "Malheureusement, votre demande de participation a été refusée par les organisateur⋅ices."
|
|
||||||
}
|
}
|
@ -96,15 +96,13 @@ export interface IEvent {
|
|||||||
slug: string;
|
slug: string;
|
||||||
description: string;
|
description: string;
|
||||||
category: Category | null;
|
category: Category | null;
|
||||||
|
|
||||||
beginsOn: Date;
|
beginsOn: Date;
|
||||||
endsOn: Date | null;
|
endsOn: Date | null;
|
||||||
publishAt: Date;
|
publishAt: Date;
|
||||||
|
|
||||||
status: EventStatus;
|
status: EventStatus;
|
||||||
visibility: EventVisibility;
|
visibility: EventVisibility;
|
||||||
|
|
||||||
joinOptions: EventJoinOptions;
|
joinOptions: EventJoinOptions;
|
||||||
|
draft: boolean;
|
||||||
|
|
||||||
picture: IPicture | null;
|
picture: IPicture | null;
|
||||||
|
|
||||||
@ -176,6 +174,7 @@ export class EventModel implements IEvent {
|
|||||||
category: Category | null = Category.MEETING;
|
category: Category | null = Category.MEETING;
|
||||||
joinOptions = EventJoinOptions.FREE;
|
joinOptions = EventJoinOptions.FREE;
|
||||||
status = EventStatus.CONFIRMED;
|
status = EventStatus.CONFIRMED;
|
||||||
|
draft = true;
|
||||||
|
|
||||||
publishAt = new Date();
|
publishAt = new Date();
|
||||||
|
|
||||||
@ -210,8 +209,8 @@ export class EventModel implements IEvent {
|
|||||||
|
|
||||||
this.status = hash.status;
|
this.status = hash.status;
|
||||||
this.visibility = hash.visibility;
|
this.visibility = hash.visibility;
|
||||||
|
|
||||||
this.joinOptions = hash.joinOptions;
|
this.joinOptions = hash.joinOptions;
|
||||||
|
this.draft = hash.draft;
|
||||||
|
|
||||||
this.picture = hash.picture;
|
this.picture = hash.picture;
|
||||||
|
|
||||||
@ -240,6 +239,7 @@ export class EventModel implements IEvent {
|
|||||||
status: this.status,
|
status: this.status,
|
||||||
visibility: this.visibility,
|
visibility: this.visibility,
|
||||||
joinOptions: this.joinOptions,
|
joinOptions: this.joinOptions,
|
||||||
|
draft: this.draft,
|
||||||
tags: this.tags.map(t => t.title),
|
tags: this.tags.map(t => t.title),
|
||||||
picture: this.picture,
|
picture: this.picture,
|
||||||
onlineAddress: this.onlineAddress,
|
onlineAddress: this.onlineAddress,
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
{{ $t('Change') }}
|
{{ $t('Change') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
<b-modal :active.sync="isComponentModalActive" has-modal-card>
|
<b-modal :active.sync="isComponentModalActive" has-modal-card>
|
||||||
<identity-picker :currentIdentity="currentIdentity" @input="relay" />
|
<identity-picker v-model="currentIdentity" @input="relay" />
|
||||||
</b-modal>
|
</b-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="columns is-centered">
|
<div class="columns is-centered">
|
||||||
<form class="column is-two-thirds-desktop">
|
<form class="column is-two-thirds-desktop" ref="form">
|
||||||
<h2 class="subtitle">
|
<h2 class="subtitle">
|
||||||
{{ $t('General information') }}
|
{{ $t('General information') }}
|
||||||
</h2>
|
</h2>
|
||||||
@ -170,14 +170,16 @@
|
|||||||
{{ $t('Cancel') }}
|
{{ $t('Cancel') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
</span>
|
</span>
|
||||||
<span class="navbar-item" v-if="isUpdate === false">
|
<!-- If an event has been published we can't make it draft anymore -->
|
||||||
<b-button type="is-primary" outlined>
|
<span class="navbar-item" v-if="event.draft === true">
|
||||||
|
<b-button type="is-primary" outlined @click="createOrUpdateDraft">
|
||||||
{{ $t('Save draft') }}
|
{{ $t('Save draft') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
</span>
|
</span>
|
||||||
<span class="navbar-item">
|
<span class="navbar-item">
|
||||||
<b-button type="is-primary" @click="createOrUpdate" @keyup.enter="createOrUpdate">
|
<b-button type="is-primary" @click="createOrUpdatePublish" @keyup.enter="createOrUpdatePublish">
|
||||||
<span v-if="isUpdate === false">{{ $t('Create my event') }}</span>
|
<span v-if="isUpdate === false">{{ $t('Create my event') }}</span>
|
||||||
|
<span v-else-if="event.draft === true"> {{ $t('Publish') }}</span>
|
||||||
<span v-else> {{ $t('Update my event') }}</span>
|
<span v-else> {{ $t('Update my event') }}</span>
|
||||||
</b-button>
|
</b-button>
|
||||||
</span>
|
</span>
|
||||||
@ -238,7 +240,7 @@ import {
|
|||||||
EventVisibility, IEvent,
|
EventVisibility, IEvent,
|
||||||
} from '@/types/event.model';
|
} from '@/types/event.model';
|
||||||
import { CURRENT_ACTOR_CLIENT } from '@/graphql/actor';
|
import { CURRENT_ACTOR_CLIENT } from '@/graphql/actor';
|
||||||
import { Person } from '@/types/actor';
|
import { IActor, Person } from '@/types/actor';
|
||||||
import PictureUpload from '@/components/PictureUpload.vue';
|
import PictureUpload from '@/components/PictureUpload.vue';
|
||||||
import Editor from '@/components/Editor.vue';
|
import Editor from '@/components/Editor.vue';
|
||||||
import DateTimePicker from '@/components/Event/DateTimePicker.vue';
|
import DateTimePicker from '@/components/Event/DateTimePicker.vue';
|
||||||
@ -312,7 +314,6 @@ export default class EditEvent extends Vue {
|
|||||||
this.observer = new IntersectionObserver((entries, observer) => {
|
this.observer = new IntersectionObserver((entries, observer) => {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
if (entry) {
|
if (entry) {
|
||||||
console.log(entry);
|
|
||||||
this.showFixedNavbar = !entry.isIntersecting;
|
this.showFixedNavbar = !entry.isIntersecting;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,12 +323,29 @@ export default class EditEvent extends Vue {
|
|||||||
this.observer.observe(this.$refs.bottomObserver as Element);
|
this.observer.observe(this.$refs.bottomObserver as Element);
|
||||||
}
|
}
|
||||||
|
|
||||||
createOrUpdate(e: Event) {
|
createOrUpdateDraft(e: Event) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
if (this.validateForm()) {
|
||||||
|
if (this.eventId) return this.updateEvent();
|
||||||
|
|
||||||
if (this.eventId) return this.updateEvent();
|
return this.createEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this.createEvent();
|
createOrUpdatePublish(e: Event) {
|
||||||
|
if (this.validateForm()) {
|
||||||
|
this.event.draft = false;
|
||||||
|
this.createOrUpdateDraft(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private validateForm() {
|
||||||
|
const form = this.$refs.form as HTMLFormElement;
|
||||||
|
if (form.checkValidity()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
form.reportValidity();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createEvent() {
|
async createEvent() {
|
||||||
@ -412,13 +430,16 @@ export default class EditEvent extends Vue {
|
|||||||
* Confirm cancel
|
* Confirm cancel
|
||||||
*/
|
*/
|
||||||
confirmGoBack() {
|
confirmGoBack() {
|
||||||
|
if (!this.isEventModified) {
|
||||||
|
return this.$router.go(-1);
|
||||||
|
}
|
||||||
const title: string = this.isUpdate ?
|
const title: string = this.isUpdate ?
|
||||||
this.$t('Cancel edition') as string :
|
this.$t('Cancel edition') as string :
|
||||||
this.$t('Cancel creation') as string;
|
this.$t('Cancel creation') as string;
|
||||||
const message: string = this.isUpdate ?
|
const message: string = this.isUpdate ?
|
||||||
this.$t('Are you sure you want to cancel the event edition? You\'ll lose all modifications.',
|
this.$t("Are you sure you want to cancel the event edition? You'll lose all modifications.",
|
||||||
{ title: this.event.title }) as string :
|
{ title: this.event.title }) as string :
|
||||||
this.$t('Are you sure you want to cancel the event creation? You\'ll lose all modifications.',
|
this.$t("Are you sure you want to cancel the event creation? You'll lose all modifications.",
|
||||||
{ title: this.event.title }) as string;
|
{ title: this.event.title }) as string;
|
||||||
|
|
||||||
this.$buefy.dialog.confirm({
|
this.$buefy.dialog.confirm({
|
||||||
|
@ -18,15 +18,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<h1 class="title">{{ event.title }}</h1>
|
<h1 class="title">{{ event.title }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="has-text-right">
|
<div class="has-text-right" v-if="new Date(endDate) > new Date()">
|
||||||
<small v-if="event.participantStats.approved > 0 && !actorIsParticipant">
|
<small v-if="event.participantStats.approved > 0 && !actorIsParticipant">
|
||||||
{{ $tc('One person is going', event.participantStats.approved, {approved: event.participantStats.approved}) }}
|
{{ $tc('One person is going', event.participantStats.approved, {approved: event.participantStats.approved}) }}
|
||||||
</small>
|
</small>
|
||||||
<small v-else>
|
<small v-else-if="event.participantStats.approved > 0 && actorIsParticipant">
|
||||||
{{ $tc('You and one other person are going to this event', event.participantStats.approved - 1, {approved: event.participantStats.approved - 1}) }}
|
{{ $tc('You and one other person are going to this event', event.participantStats.approved - 1, {approved: event.participantStats.approved - 1}) }}
|
||||||
</small>
|
</small>
|
||||||
<participation-button
|
<participation-button
|
||||||
v-if="currentActor.id && !actorIsOrganizer"
|
v-if="currentActor.id && !actorIsOrganizer && !event.draft"
|
||||||
:participation="participations[0]"
|
:participation="participations[0]"
|
||||||
:current-actor="currentActor"
|
:current-actor="currentActor"
|
||||||
@joinEvent="joinEvent"
|
@joinEvent="joinEvent"
|
||||||
@ -34,15 +34,25 @@
|
|||||||
@confirmLeave="confirmLeave"
|
@confirmLeave="confirmLeave"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<button class="button is-primary" type="button" slot="trigger" disabled>
|
||||||
|
<template>
|
||||||
|
<span>{{ $t('Event already passed')}}</span>
|
||||||
|
</template>
|
||||||
|
<b-icon icon="menu-down"></b-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="metadata columns">
|
<div class="metadata columns">
|
||||||
<div class="column is-three-quarters-desktop">
|
<div class="column is-three-quarters-desktop">
|
||||||
<p class="tags" v-if="event.category || event.tags.length > 0">
|
<p class="tags" v-if="event.category || event.tags.length > 0">
|
||||||
|
<b-tag type="is-warning" size="is-medium" v-if="event.draft">{{ $t('Draft') }}</b-tag>
|
||||||
<!-- <span class="tag" v-if="event.category">{{ event.category }}</span>-->
|
<!-- <span class="tag" v-if="event.category">{{ event.category }}</span>-->
|
||||||
<span class="tag" v-if="event.tags" v-for="tag in event.tags">{{ tag.title }}</span>
|
<b-tag type="is-success" v-if="event.tags" v-for="tag in event.tags">{{ tag.title }}</b-tag>
|
||||||
<span class="visibility">
|
<span v-if="event.tags > 0">⋅</span>
|
||||||
<span v-if="event.visibility === EventVisibility.PUBLIC">{{ $t('Public event') }}</span>
|
<span class="visibility" v-if="!event.draft">
|
||||||
<span v-if="event.visibility === EventVisibility.UNLISTED">{{ $t('Private event') }}</span>
|
<b-tag type="is-info" v-if="event.visibility === EventVisibility.PUBLIC">{{ $t('Public event') }}</b-tag>
|
||||||
|
<b-tag type="is-info" v-if="event.visibility === EventVisibility.UNLISTED">{{ $t('Private event') }}</b-tag>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<div class="date-and-add-to-calendar">
|
<div class="date-and-add-to-calendar">
|
||||||
@ -50,7 +60,7 @@
|
|||||||
<b-icon icon="calendar-clock" />
|
<b-icon icon="calendar-clock" />
|
||||||
<event-full-date :beginsOn="event.beginsOn" :endsOn="event.endsOn" />
|
<event-full-date :beginsOn="event.beginsOn" :endsOn="event.endsOn" />
|
||||||
</div>
|
</div>
|
||||||
<a class="add-to-calendar" @click="downloadIcsEvent()">
|
<a class="add-to-calendar" @click="downloadIcsEvent()" v-if="!event.draft">
|
||||||
<b-icon icon="calendar-plus" />
|
<b-icon icon="calendar-plus" />
|
||||||
{{ $t('Add to my calendar') }}
|
{{ $t('Add to my calendar') }}
|
||||||
</a>
|
</a>
|
||||||
@ -61,7 +71,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="column sidebar">
|
<div class="column sidebar">
|
||||||
<div class="field has-addons" v-if="currentActor.id">
|
<div class="field has-addons" v-if="currentActor.id">
|
||||||
<p class="control" v-if="actorIsOrganizer">
|
<p class="control" v-if="actorIsOrganizer || event.draft">
|
||||||
<router-link
|
<router-link
|
||||||
class="button"
|
class="button"
|
||||||
:to="{ name: 'EditEvent', params: {eventId: event.uuid}}"
|
:to="{ name: 'EditEvent', params: {eventId: event.uuid}}"
|
||||||
@ -69,7 +79,7 @@
|
|||||||
{{ $t('Edit') }}
|
{{ $t('Edit') }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</p>
|
</p>
|
||||||
<p class="control" v-if="actorIsOrganizer">
|
<p class="control" v-if="actorIsOrganizer || event.draft">
|
||||||
<a class="button is-danger" @click="openDeleteEventModalWrapper">
|
<a class="button is-danger" @click="openDeleteEventModalWrapper">
|
||||||
{{ $t('Delete') }}
|
{{ $t('Delete') }}
|
||||||
</a>
|
</a>
|
||||||
@ -133,7 +143,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<section class="share">
|
<section class="share" v-if="!event.draft">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column is-half has-text-centered">
|
<div class="column is-half has-text-centered">
|
||||||
@ -433,6 +443,10 @@ export default class Event extends EventMixin {
|
|||||||
return this.participations.length > 0 && this.participations[0].role === ParticipantRole.CREATOR;
|
return this.participations.length > 0 && this.participations[0].role === ParticipantRole.CREATOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get endDate() {
|
||||||
|
return this.event.endsOn !== null && this.event.endsOn > this.event.beginsOn ? this.event.endsOn : this.event.beginsOn;
|
||||||
|
}
|
||||||
|
|
||||||
get twitterShareUrl(): string {
|
get twitterShareUrl(): string {
|
||||||
return `https://twitter.com/intent/tweet?url=${encodeURIComponent(this.event.url)}&text=${this.event.title}`;
|
return `https://twitter.com/intent/tweet?url=${encodeURIComponent(this.event.url)}&text=${this.event.title}`;
|
||||||
}
|
}
|
||||||
@ -597,18 +611,14 @@ export default class Event extends EventMixin {
|
|||||||
|
|
||||||
p.tags {
|
p.tags {
|
||||||
span {
|
span {
|
||||||
&.tag {
|
&.tag.is-success {
|
||||||
&::before {
|
&::before {
|
||||||
content: '#';
|
content: '#';
|
||||||
}
|
}
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
color: #111111;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.visibility::before {
|
|
||||||
content: "⋅"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
margin: auto 5px;
|
margin: auto 5px;
|
||||||
}
|
}
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
@ -26,6 +26,19 @@
|
|||||||
v-if="hasMoreFutureParticipations && (futureParticipations.length === limit)" @click="loadMoreFutureParticipations" size="is-large" type="is-primary">{{ $t('Load more') }}</b-button>
|
v-if="hasMoreFutureParticipations && (futureParticipations.length === limit)" @click="loadMoreFutureParticipations" size="is-large" type="is-primary">{{ $t('Load more') }}</b-button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section v-if="drafts.length > 0">
|
||||||
|
<h2 class="subtitle">
|
||||||
|
{{ $t('Drafts') }}
|
||||||
|
</h2>
|
||||||
|
<div class="columns is-multiline">
|
||||||
|
<EventCard
|
||||||
|
v-for="draft in drafts"
|
||||||
|
:key="draft.uuid"
|
||||||
|
:event="draft"
|
||||||
|
class="is-one-quarter-desktop column"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
<section v-if="pastParticipations.length > 0">
|
<section v-if="pastParticipations.length > 0">
|
||||||
<h2 class="subtitle">
|
<h2 class="subtitle">
|
||||||
{{ $t('Past events') }}
|
{{ $t('Past events') }}
|
||||||
@ -56,13 +69,15 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||||
import { LOGGED_USER_PARTICIPATIONS } from '@/graphql/actor';
|
import { LOGGED_USER_PARTICIPATIONS, LOGGED_USER_DRAFTS } from '@/graphql/actor';
|
||||||
import { IParticipant, Participant } from '@/types/event.model';
|
import { EventModel, IEvent, IParticipant, Participant } from '@/types/event.model';
|
||||||
import EventListCard from '@/components/Event/EventListCard.vue';
|
import EventListCard from '@/components/Event/EventListCard.vue';
|
||||||
|
import EventCard from '@/components/Event/EventCard.vue';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
|
EventCard,
|
||||||
EventListCard,
|
EventListCard,
|
||||||
},
|
},
|
||||||
apollo: {
|
apollo: {
|
||||||
@ -75,6 +90,14 @@ import EventListCard from '@/components/Event/EventListCard.vue';
|
|||||||
},
|
},
|
||||||
update: data => data.loggedUser.participations.map(participation => new Participant(participation)),
|
update: data => data.loggedUser.participations.map(participation => new Participant(participation)),
|
||||||
},
|
},
|
||||||
|
drafts: {
|
||||||
|
query: LOGGED_USER_DRAFTS,
|
||||||
|
variables: {
|
||||||
|
page: 1,
|
||||||
|
limit: 10,
|
||||||
|
},
|
||||||
|
update: data => data.loggedUser.drafts.map(event => new EventModel(event)),
|
||||||
|
},
|
||||||
pastParticipations: {
|
pastParticipations: {
|
||||||
query: LOGGED_USER_PARTICIPATIONS,
|
query: LOGGED_USER_PARTICIPATIONS,
|
||||||
variables: {
|
variables: {
|
||||||
@ -97,6 +120,8 @@ export default class MyEvents extends Vue {
|
|||||||
pastParticipations: IParticipant[] = [];
|
pastParticipations: IParticipant[] = [];
|
||||||
hasMorePastParticipations: boolean = true;
|
hasMorePastParticipations: boolean = true;
|
||||||
|
|
||||||
|
drafts: IEvent[] = [];
|
||||||
|
|
||||||
private monthlyParticipations(participations: IParticipant[]): Map<string, Participant[]> {
|
private monthlyParticipations(participations: IParticipant[]): Map<string, Participant[]> {
|
||||||
const res = participations.filter(({ event }) => event.beginsOn != null);
|
const res = participations.filter(({ event }) => event.beginsOn != null);
|
||||||
res.sort(
|
res.sort(
|
||||||
|
@ -32,6 +32,7 @@ defmodule Mobilizon.Events.Event do
|
|||||||
ends_on: DateTime.t(),
|
ends_on: DateTime.t(),
|
||||||
title: String.t(),
|
title: String.t(),
|
||||||
status: EventStatus.t(),
|
status: EventStatus.t(),
|
||||||
|
draft: boolean,
|
||||||
visibility: EventVisibility.t(),
|
visibility: EventVisibility.t(),
|
||||||
join_options: JoinOptions.t(),
|
join_options: JoinOptions.t(),
|
||||||
publish_at: DateTime.t(),
|
publish_at: DateTime.t(),
|
||||||
@ -57,6 +58,7 @@ defmodule Mobilizon.Events.Event do
|
|||||||
:ends_on,
|
:ends_on,
|
||||||
:category,
|
:category,
|
||||||
:status,
|
:status,
|
||||||
|
:draft,
|
||||||
:visibility,
|
:visibility,
|
||||||
:publish_at,
|
:publish_at,
|
||||||
:online_address,
|
:online_address,
|
||||||
@ -74,6 +76,7 @@ defmodule Mobilizon.Events.Event do
|
|||||||
:ends_on,
|
:ends_on,
|
||||||
:category,
|
:category,
|
||||||
:status,
|
:status,
|
||||||
|
:draft,
|
||||||
:visibility,
|
:visibility,
|
||||||
:join_options,
|
:join_options,
|
||||||
:publish_at,
|
:publish_at,
|
||||||
@ -93,6 +96,7 @@ defmodule Mobilizon.Events.Event do
|
|||||||
field(:ends_on, :utc_datetime)
|
field(:ends_on, :utc_datetime)
|
||||||
field(:title, :string)
|
field(:title, :string)
|
||||||
field(:status, EventStatus, default: :confirmed)
|
field(:status, EventStatus, default: :confirmed)
|
||||||
|
field(:draft, :boolean, default: false)
|
||||||
field(:visibility, EventVisibility, default: :public)
|
field(:visibility, EventVisibility, default: :public)
|
||||||
field(:join_options, JoinOptions, default: :free)
|
field(:join_options, JoinOptions, default: :free)
|
||||||
field(:publish_at, :utc_datetime)
|
field(:publish_at, :utc_datetime)
|
||||||
|
@ -169,6 +169,7 @@ defmodule Mobilizon.Events do
|
|||||||
url
|
url
|
||||||
|> event_by_url_query()
|
|> event_by_url_query()
|
||||||
|> filter_public_visibility()
|
|> filter_public_visibility()
|
||||||
|
|> filter_draft()
|
||||||
|> preload_for_event()
|
|> preload_for_event()
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
|
|
||||||
@ -190,18 +191,32 @@ defmodule Mobilizon.Events do
|
|||||||
url
|
url
|
||||||
|> event_by_url_query()
|
|> event_by_url_query()
|
||||||
|> filter_public_visibility()
|
|> filter_public_visibility()
|
||||||
|
|> filter_draft()
|
||||||
|> preload_for_event()
|
|> preload_for_event()
|
||||||
|> Repo.one!()
|
|> Repo.one!()
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Gets an event by its UUID, with all associations loaded.
|
Gets a public event by its UUID, with all associations loaded.
|
||||||
"""
|
"""
|
||||||
@spec get_public_event_by_uuid_with_preload(String.t()) :: Event.t() | nil
|
@spec get_public_event_by_uuid_with_preload(String.t()) :: Event.t() | nil
|
||||||
def get_public_event_by_uuid_with_preload(uuid) do
|
def get_public_event_by_uuid_with_preload(uuid) do
|
||||||
uuid
|
uuid
|
||||||
|> event_by_uuid_query()
|
|> event_by_uuid_query()
|
||||||
|> filter_public_visibility()
|
|> filter_public_visibility()
|
||||||
|
|> filter_draft()
|
||||||
|
|> preload_for_event()
|
||||||
|
|> Repo.one()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Gets an event by its UUID, with all associations loaded.
|
||||||
|
"""
|
||||||
|
@spec get_own_event_by_uuid_with_preload(String.t(), integer()) :: Event.t() | nil
|
||||||
|
def get_own_event_by_uuid_with_preload(uuid, user_id) do
|
||||||
|
uuid
|
||||||
|
|> event_by_uuid_query()
|
||||||
|
|> user_events_query(user_id)
|
||||||
|> preload_for_event()
|
|> preload_for_event()
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
end
|
end
|
||||||
@ -215,6 +230,7 @@ defmodule Mobilizon.Events do
|
|||||||
|> upcoming_public_event_for_actor_query()
|
|> upcoming_public_event_for_actor_query()
|
||||||
|> filter_public_visibility()
|
|> filter_public_visibility()
|
||||||
|> filter_not_event_uuid(not_event_uuid)
|
|> filter_not_event_uuid(not_event_uuid)
|
||||||
|
|> filter_draft()
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -223,16 +239,18 @@ defmodule Mobilizon.Events do
|
|||||||
"""
|
"""
|
||||||
@spec create_event(map) :: {:ok, Event.t()} | {:error, Ecto.Changeset.t()}
|
@spec create_event(map) :: {:ok, Event.t()} | {:error, Ecto.Changeset.t()}
|
||||||
def create_event(attrs \\ %{}) do
|
def create_event(attrs \\ %{}) do
|
||||||
with {:ok, %Event{} = event} <- do_create_event(attrs),
|
with {:ok, %Event{draft: false} = event} <- do_create_event(attrs),
|
||||||
{:ok, %Participant{} = _participant} <-
|
{:ok, %Participant{} = _participant} <-
|
||||||
%Participant{}
|
create_participant(%{
|
||||||
|> Participant.changeset(%{
|
|
||||||
actor_id: event.organizer_actor_id,
|
actor_id: event.organizer_actor_id,
|
||||||
role: :creator,
|
role: :creator,
|
||||||
event_id: event.id
|
event_id: event.id
|
||||||
})
|
}) do
|
||||||
|> Repo.insert() do
|
|
||||||
{:ok, event}
|
{:ok, event}
|
||||||
|
else
|
||||||
|
# We don't create a creator participant if the event is a draft
|
||||||
|
{:ok, %Event{draft: true} = event} -> {:ok, event}
|
||||||
|
err -> err
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -262,10 +280,24 @@ defmodule Mobilizon.Events do
|
|||||||
Updates an event.
|
Updates an event.
|
||||||
"""
|
"""
|
||||||
@spec update_event(Event.t(), map) :: {:ok, Event.t()} | {:error, Ecto.Changeset.t()}
|
@spec update_event(Event.t(), map) :: {:ok, Event.t()} | {:error, Ecto.Changeset.t()}
|
||||||
def update_event(%Event{} = old_event, attrs) do
|
def update_event(
|
||||||
|
%Event{draft: old_draft_status, id: event_id, organizer_actor_id: organizer_actor_id} =
|
||||||
|
old_event,
|
||||||
|
attrs
|
||||||
|
) do
|
||||||
with %Ecto.Changeset{changes: changes} = changeset <-
|
with %Ecto.Changeset{changes: changes} = changeset <-
|
||||||
old_event |> Repo.preload(:tags) |> Event.update_changeset(attrs) do
|
old_event |> Repo.preload(:tags) |> Event.update_changeset(attrs) do
|
||||||
with {:ok, %Event{} = new_event} <- Repo.update(changeset) do
|
with {:ok, %Event{draft: new_draft_status} = new_event} <- Repo.update(changeset) do
|
||||||
|
# If the event is no longer a draft
|
||||||
|
if old_draft_status == true && new_draft_status == false do
|
||||||
|
{:ok, %Participant{} = _participant} =
|
||||||
|
create_participant(%{
|
||||||
|
event_id: event_id,
|
||||||
|
role: :creator,
|
||||||
|
actor_id: organizer_actor_id
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
Mobilizon.Service.Events.Tool.calculate_event_diff_and_send_notifications(
|
Mobilizon.Service.Events.Tool.calculate_event_diff_and_send_notifications(
|
||||||
old_event,
|
old_event,
|
||||||
new_event,
|
new_event,
|
||||||
@ -309,6 +341,7 @@ defmodule Mobilizon.Events do
|
|||||||
|> sort(sort, direction)
|
|> sort(sort, direction)
|
||||||
|> filter_future_events(is_future)
|
|> filter_future_events(is_future)
|
||||||
|> filter_unlisted(is_unlisted)
|
|> filter_unlisted(is_unlisted)
|
||||||
|
|> filter_draft()
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -320,6 +353,7 @@ defmodule Mobilizon.Events do
|
|||||||
tags
|
tags
|
||||||
|> Enum.map(& &1.id)
|
|> Enum.map(& &1.id)
|
||||||
|> events_by_tags_query(limit)
|
|> events_by_tags_query(limit)
|
||||||
|
|> filter_draft()
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -333,6 +367,7 @@ defmodule Mobilizon.Events do
|
|||||||
actor_id
|
actor_id
|
||||||
|> event_for_actor_query()
|
|> event_for_actor_query()
|
||||||
|> filter_public_visibility()
|
|> filter_public_visibility()
|
||||||
|
|> filter_draft()
|
||||||
|> preload_for_event()
|
|> preload_for_event()
|
||||||
|> Page.paginate(page, limit)
|
|> Page.paginate(page, limit)
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
@ -345,6 +380,15 @@ defmodule Mobilizon.Events do
|
|||||||
{:ok, events, events_count}
|
{:ok, events, events_count}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec list_drafts_for_user(integer, integer | nil, integer | nil) :: [Event.t()]
|
||||||
|
def list_drafts_for_user(user_id, page \\ nil, limit \\ nil) do
|
||||||
|
Event
|
||||||
|
|> user_events_query(user_id)
|
||||||
|
|> filter_draft(true)
|
||||||
|
|> Page.paginate(page, limit)
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Finds close events to coordinates.
|
Finds close events to coordinates.
|
||||||
Radius is in meters and defaults to 50km.
|
Radius is in meters and defaults to 50km.
|
||||||
@ -354,6 +398,7 @@ defmodule Mobilizon.Events do
|
|||||||
"SRID=#{srid};POINT(#{lon} #{lat})"
|
"SRID=#{srid};POINT(#{lon} #{lat})"
|
||||||
|> Geo.WKT.decode!()
|
|> Geo.WKT.decode!()
|
||||||
|> close_events_query(radius)
|
|> close_events_query(radius)
|
||||||
|
|> filter_draft()
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -364,6 +409,7 @@ defmodule Mobilizon.Events do
|
|||||||
def count_local_events do
|
def count_local_events do
|
||||||
count_local_events_query()
|
count_local_events_query()
|
||||||
|> filter_public_visibility()
|
|> filter_public_visibility()
|
||||||
|
|> filter_draft()
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1134,6 +1180,16 @@ defmodule Mobilizon.Events do
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec user_events_query(Ecto.Query.t(), number()) :: Ecto.Query.t()
|
||||||
|
defp user_events_query(query, user_id) do
|
||||||
|
from(
|
||||||
|
e in query,
|
||||||
|
join: a in Actor,
|
||||||
|
on: a.id == e.organizer_actor_id,
|
||||||
|
where: a.user_id == ^user_id
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
@spec events_by_name_query(String.t()) :: Ecto.Query.t()
|
@spec events_by_name_query(String.t()) :: Ecto.Query.t()
|
||||||
defp events_by_name_query(name) do
|
defp events_by_name_query(name) do
|
||||||
from(
|
from(
|
||||||
@ -1372,6 +1428,11 @@ defmodule Mobilizon.Events do
|
|||||||
from(e in query, where: e.uuid != ^not_event_uuid)
|
from(e in query, where: e.uuid != ^not_event_uuid)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec filter_draft(Ecto.Query.t(), boolean) :: Ecto.Query.t()
|
||||||
|
defp filter_draft(query, is_draft \\ false) do
|
||||||
|
from(e in query, where: e.draft == ^is_draft)
|
||||||
|
end
|
||||||
|
|
||||||
@spec filter_future_events(Ecto.Query.t(), boolean) :: Ecto.Query.t()
|
@spec filter_future_events(Ecto.Query.t(), boolean) :: Ecto.Query.t()
|
||||||
defp filter_future_events(query, true) do
|
defp filter_future_events(query, true) do
|
||||||
from(q in query, where: q.begins_on > ^DateTime.utc_now())
|
from(q in query, where: q.begins_on > ^DateTime.utc_now())
|
||||||
|
@ -31,7 +31,8 @@ defmodule MobilizonWeb.API.Events do
|
|||||||
to: args.to,
|
to: args.to,
|
||||||
actor: organizer_actor,
|
actor: organizer_actor,
|
||||||
object: event,
|
object: event,
|
||||||
local: true
|
# For now we don't federate drafts but it will be needed if we want to edit them as groups
|
||||||
|
local: args.metadata.draft == false
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -65,7 +66,7 @@ defmodule MobilizonWeb.API.Events do
|
|||||||
actor: organizer_actor.url,
|
actor: organizer_actor.url,
|
||||||
cc: [],
|
cc: [],
|
||||||
object: event,
|
object: event,
|
||||||
local: true
|
local: args.metadata.draft == false
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -95,7 +96,8 @@ defmodule MobilizonWeb.API.Events do
|
|||||||
join_options: Map.get(args, :join_options),
|
join_options: Map.get(args, :join_options),
|
||||||
status: Map.get(args, :status),
|
status: Map.get(args, :status),
|
||||||
online_address: Map.get(args, :online_address),
|
online_address: Map.get(args, :online_address),
|
||||||
phone_address: Map.get(args, :phone_address)
|
phone_address: Map.get(args, :phone_address),
|
||||||
|
draft: Map.get(args, :draft)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -31,6 +31,20 @@ defmodule MobilizonWeb.Resolvers.Event do
|
|||||||
{:error, :events_max_limit_reached}
|
{:error, :events_max_limit_reached}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def find_event(
|
||||||
|
_parent,
|
||||||
|
%{uuid: uuid},
|
||||||
|
%{context: %{current_user: %User{id: user_id}}} = _resolution
|
||||||
|
) do
|
||||||
|
case {:has_event, Mobilizon.Events.get_own_event_by_uuid_with_preload(uuid, user_id)} do
|
||||||
|
{:has_event, %Event{} = event} ->
|
||||||
|
{:ok, Map.put(event, :organizer_actor, Person.proxify_pictures(event.organizer_actor))}
|
||||||
|
|
||||||
|
{:has_event, _} ->
|
||||||
|
{:error, "Event with UUID #{uuid} not found"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def find_event(_parent, %{uuid: uuid}, _resolution) do
|
def find_event(_parent, %{uuid: uuid}, _resolution) do
|
||||||
case {:has_event, Mobilizon.Events.get_public_event_by_uuid_with_preload(uuid)} do
|
case {:has_event, Mobilizon.Events.get_public_event_by_uuid_with_preload(uuid)} do
|
||||||
{:has_event, %Event{} = event} ->
|
{:has_event, %Event{} = event} ->
|
||||||
@ -264,6 +278,9 @@ defmodule MobilizonWeb.Resolvers.Event do
|
|||||||
else
|
else
|
||||||
{:is_owned, nil} ->
|
{:is_owned, nil} ->
|
||||||
{:error, "Organizer actor id is not owned by the user"}
|
{:error, "Organizer actor id is not owned by the user"}
|
||||||
|
|
||||||
|
{:error, %Ecto.Changeset{} = error} ->
|
||||||
|
{:error, error}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -243,6 +243,19 @@ defmodule MobilizonWeb.Resolvers.User do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns the list of draft events for the current user
|
||||||
|
"""
|
||||||
|
def user_drafted_events(%User{id: user_id}, args, %{
|
||||||
|
context: %{current_user: %User{id: logged_user_id}}
|
||||||
|
}) do
|
||||||
|
with {:same_user, true} <- {:same_user, user_id == logged_user_id},
|
||||||
|
events <-
|
||||||
|
Events.list_drafts_for_user(user_id, Map.get(args, :page), Map.get(args, :limit)) do
|
||||||
|
{:ok, events}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def change_password(_parent, %{old_password: old_password, new_password: new_password}, %{
|
def change_password(_parent, %{old_password: old_password, new_password: new_password}, %{
|
||||||
context: %{current_user: %User{password_hash: old_password_hash} = user}
|
context: %{current_user: %User{password_hash: old_password_hash} = user}
|
||||||
}) do
|
}) do
|
||||||
|
@ -6,6 +6,7 @@ defmodule MobilizonWeb.Schema.EventType do
|
|||||||
use Absinthe.Schema.Notation
|
use Absinthe.Schema.Notation
|
||||||
|
|
||||||
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
|
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
|
||||||
|
import MobilizonWeb.Schema.Utils
|
||||||
|
|
||||||
alias Mobilizon.{Actors, Addresses}
|
alias Mobilizon.{Actors, Addresses}
|
||||||
|
|
||||||
@ -60,6 +61,8 @@ defmodule MobilizonWeb.Schema.EventType do
|
|||||||
|
|
||||||
field(:category, :string, description: "The event's category")
|
field(:category, :string, description: "The event's category")
|
||||||
|
|
||||||
|
field(:draft, :boolean, description: "Whether or not the event is a draft")
|
||||||
|
|
||||||
field(:participant_stats, :participant_stats, resolve: &Event.stats_participants_for_event/3)
|
field(:participant_stats, :participant_stats, resolve: &Event.stats_participants_for_event/3)
|
||||||
|
|
||||||
field(:participants, list_of(:participant), description: "The event's participants") do
|
field(:participants, list_of(:participant), description: "The event's participants") do
|
||||||
@ -252,8 +255,9 @@ defmodule MobilizonWeb.Schema.EventType do
|
|||||||
arg(:category, :string, default_value: "meeting")
|
arg(:category, :string, default_value: "meeting")
|
||||||
arg(:physical_address, :address_input)
|
arg(:physical_address, :address_input)
|
||||||
arg(:options, :event_options_input)
|
arg(:options, :event_options_input)
|
||||||
|
arg(:draft, :boolean, default_value: false)
|
||||||
|
|
||||||
resolve(&Event.create_event/3)
|
resolve(handle_errors(&Event.create_event/3))
|
||||||
end
|
end
|
||||||
|
|
||||||
@desc "Update an event"
|
@desc "Update an event"
|
||||||
@ -280,8 +284,9 @@ defmodule MobilizonWeb.Schema.EventType do
|
|||||||
arg(:category, :string)
|
arg(:category, :string)
|
||||||
arg(:physical_address, :address_input)
|
arg(:physical_address, :address_input)
|
||||||
arg(:options, :event_options_input)
|
arg(:options, :event_options_input)
|
||||||
|
arg(:draft, :boolean)
|
||||||
|
|
||||||
resolve(&Event.update_event/3)
|
resolve(handle_errors(&Event.update_event/3))
|
||||||
end
|
end
|
||||||
|
|
||||||
@desc "Delete an event"
|
@desc "Delete an event"
|
||||||
|
@ -49,7 +49,7 @@ defmodule MobilizonWeb.Schema.UserType do
|
|||||||
field(:locale, :string, description: "The user's locale")
|
field(:locale, :string, description: "The user's locale")
|
||||||
|
|
||||||
field(:participations, list_of(:participant),
|
field(:participations, list_of(:participant),
|
||||||
description: "The list of events this user goes to"
|
description: "The list of participations this user has"
|
||||||
) do
|
) do
|
||||||
arg(:after_datetime, :datetime)
|
arg(:after_datetime, :datetime)
|
||||||
arg(:before_datetime, :datetime)
|
arg(:before_datetime, :datetime)
|
||||||
@ -57,6 +57,12 @@ defmodule MobilizonWeb.Schema.UserType do
|
|||||||
arg(:limit, :integer, default_value: 10)
|
arg(:limit, :integer, default_value: 10)
|
||||||
resolve(&User.user_participations/3)
|
resolve(&User.user_participations/3)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
field(:drafts, list_of(:event), description: "The list of draft events this user has created") do
|
||||||
|
arg(:page, :integer, default_value: 1)
|
||||||
|
arg(:limit, :integer, default_value: 10)
|
||||||
|
resolve(&User.user_drafted_events/3)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
enum :user_role do
|
enum :user_role do
|
||||||
|
@ -70,6 +70,7 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Event do
|
|||||||
"status" => object["status"],
|
"status" => object["status"],
|
||||||
"online_address" => object["onlineAddress"],
|
"online_address" => object["onlineAddress"],
|
||||||
"phone_address" => object["phoneAddress"],
|
"phone_address" => object["phoneAddress"],
|
||||||
|
"draft" => object["draft"] || false,
|
||||||
"url" => object["id"],
|
"url" => object["id"],
|
||||||
"uuid" => object["uuid"],
|
"uuid" => object["uuid"],
|
||||||
"tags" => tags,
|
"tags" => tags,
|
||||||
@ -111,6 +112,7 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Event do
|
|||||||
"joinOptions" => to_string(event.join_options),
|
"joinOptions" => to_string(event.join_options),
|
||||||
"endTime" => event.ends_on |> date_to_string(),
|
"endTime" => event.ends_on |> date_to_string(),
|
||||||
"tag" => event.tags |> build_tags(),
|
"tag" => event.tags |> build_tags(),
|
||||||
|
"draft" => event.draft,
|
||||||
"id" => event.url,
|
"id" => event.url,
|
||||||
"url" => event.url
|
"url" => event.url
|
||||||
}
|
}
|
||||||
|
@ -319,6 +319,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
|
|||||||
"status" => metadata.status,
|
"status" => metadata.status,
|
||||||
"onlineAddress" => metadata.online_address,
|
"onlineAddress" => metadata.online_address,
|
||||||
"phoneAddress" => metadata.phone_address,
|
"phoneAddress" => metadata.phone_address,
|
||||||
|
"draft" => metadata.draft,
|
||||||
"uuid" => uuid,
|
"uuid" => uuid,
|
||||||
"tag" =>
|
"tag" =>
|
||||||
tags |> Enum.uniq() |> Enum.map(fn tag -> %{"type" => "Hashtag", "name" => "##{tag}"} end)
|
tags |> Enum.uniq() |> Enum.map(fn tag -> %{"type" => "Hashtag", "name" => "##{tag}"} end)
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
defmodule Mobilizon.Storage.Repo.Migrations.AddDraftFlagToEvents do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
alter table(:events) do
|
||||||
|
add(:draft, :boolean, default: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,5 +1,5 @@
|
|||||||
# source: http://localhost:4000/api
|
# source: http://localhost:4000/api
|
||||||
# timestamp: Mon Sep 30 2019 09:56:05 GMT+0200 (GMT+02:00)
|
# timestamp: Wed Oct 02 2019 16:30:43 GMT+0200 (GMT+02:00)
|
||||||
|
|
||||||
schema {
|
schema {
|
||||||
query: RootQueryType
|
query: RootQueryType
|
||||||
@ -264,6 +264,9 @@ type Event implements ActionLogObject {
|
|||||||
"""The event's description"""
|
"""The event's description"""
|
||||||
description: String
|
description: String
|
||||||
|
|
||||||
|
"""Whether or not the event is a draft"""
|
||||||
|
draft: Boolean
|
||||||
|
|
||||||
"""Datetime for when the event ends"""
|
"""Datetime for when the event ends"""
|
||||||
endsOn: DateTime
|
endsOn: DateTime
|
||||||
|
|
||||||
@ -897,6 +900,7 @@ type RootMutationType {
|
|||||||
beginsOn: DateTime!
|
beginsOn: DateTime!
|
||||||
category: String = "meeting"
|
category: String = "meeting"
|
||||||
description: String!
|
description: String!
|
||||||
|
draft: Boolean = false
|
||||||
endsOn: DateTime
|
endsOn: DateTime
|
||||||
joinOptions: EventJoinOptions = FREE
|
joinOptions: EventJoinOptions = FREE
|
||||||
onlineAddress: String
|
onlineAddress: String
|
||||||
@ -973,7 +977,7 @@ type RootMutationType {
|
|||||||
createReportNote(content: String, moderatorId: ID!, reportId: ID!): ReportNote
|
createReportNote(content: String, moderatorId: ID!, reportId: ID!): ReportNote
|
||||||
|
|
||||||
"""Create an user"""
|
"""Create an user"""
|
||||||
createUser(email: String!, password: String!): User
|
createUser(email: String!, locale: String, password: String!): User
|
||||||
|
|
||||||
"""Delete an event"""
|
"""Delete an event"""
|
||||||
deleteEvent(actorId: ID!, eventId: ID!): DeletedObject
|
deleteEvent(actorId: ID!, eventId: ID!): DeletedObject
|
||||||
@ -1030,19 +1034,20 @@ type RootMutationType {
|
|||||||
): Person
|
): Person
|
||||||
|
|
||||||
"""Resend registration confirmation token"""
|
"""Resend registration confirmation token"""
|
||||||
resendConfirmationEmail(email: String!, locale: String = "en"): String
|
resendConfirmationEmail(email: String!, locale: String): String
|
||||||
|
|
||||||
"""Reset user password"""
|
"""Reset user password"""
|
||||||
resetPassword(locale: String = "en", password: String!, token: String!): Login
|
resetPassword(locale: String = "en", password: String!, token: String!): Login
|
||||||
|
|
||||||
"""Send a link through email to reset user password"""
|
"""Send a link through email to reset user password"""
|
||||||
sendResetPassword(email: String!, locale: String = "en"): String
|
sendResetPassword(email: String!, locale: String): String
|
||||||
|
|
||||||
"""Update an event"""
|
"""Update an event"""
|
||||||
updateEvent(
|
updateEvent(
|
||||||
beginsOn: DateTime
|
beginsOn: DateTime
|
||||||
category: String
|
category: String
|
||||||
description: String
|
description: String
|
||||||
|
draft: Boolean
|
||||||
endsOn: DateTime
|
endsOn: DateTime
|
||||||
eventId: ID!
|
eventId: ID!
|
||||||
joinOptions: EventJoinOptions = FREE
|
joinOptions: EventJoinOptions = FREE
|
||||||
@ -1212,6 +1217,9 @@ type User {
|
|||||||
"""The user's default actor"""
|
"""The user's default actor"""
|
||||||
defaultActor: Person
|
defaultActor: Person
|
||||||
|
|
||||||
|
"""The list of draft events this user has created"""
|
||||||
|
drafts(limit: Int = 10, page: Int = 1): [Event]
|
||||||
|
|
||||||
"""The user's email"""
|
"""The user's email"""
|
||||||
email: String!
|
email: String!
|
||||||
|
|
||||||
@ -1221,7 +1229,10 @@ type User {
|
|||||||
"""The user's ID"""
|
"""The user's ID"""
|
||||||
id: ID!
|
id: ID!
|
||||||
|
|
||||||
"""The list of events this user goes to"""
|
"""The user's locale"""
|
||||||
|
locale: String
|
||||||
|
|
||||||
|
"""The list of participations this user has"""
|
||||||
participations(afterDatetime: DateTime, beforeDatetime: DateTime, limit: Int = 10, page: Int = 1): [Participant]
|
participations(afterDatetime: DateTime, beforeDatetime: DateTime, limit: Int = 10, page: Int = 1): [Participant]
|
||||||
|
|
||||||
"""The user's list of profiles (identities)"""
|
"""The user's list of profiles (identities)"""
|
||||||
|
@ -119,6 +119,97 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
|
|||||||
assert json_response(res, 200)["data"]["createEvent"]["title"] == "come to my event"
|
assert json_response(res, 200)["data"]["createEvent"]["title"] == "come to my event"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "create_event/3 creates an event as a draft", %{conn: conn, actor: actor, user: user} do
|
||||||
|
mutation = """
|
||||||
|
mutation {
|
||||||
|
createEvent(
|
||||||
|
title: "come to my event",
|
||||||
|
description: "it will be fine",
|
||||||
|
begins_on: "#{
|
||||||
|
DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
|
||||||
|
}",
|
||||||
|
organizer_actor_id: "#{actor.id}",
|
||||||
|
category: "birthday",
|
||||||
|
draft: true
|
||||||
|
) {
|
||||||
|
title,
|
||||||
|
uuid,
|
||||||
|
id,
|
||||||
|
draft
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
|
||||||
|
|
||||||
|
assert json_response(res, 200)["data"]["createEvent"]["title"] == "come to my event"
|
||||||
|
assert json_response(res, 200)["data"]["createEvent"]["draft"] == true
|
||||||
|
|
||||||
|
event_uuid = json_response(res, 200)["data"]["createEvent"]["uuid"]
|
||||||
|
event_id = json_response(res, 200)["data"]["createEvent"]["id"]
|
||||||
|
|
||||||
|
query = """
|
||||||
|
{
|
||||||
|
event(uuid: "#{event_uuid}") {
|
||||||
|
uuid,
|
||||||
|
draft
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> get("/api", AbsintheHelpers.query_skeleton(query, "event"))
|
||||||
|
|
||||||
|
assert hd(json_response(res, 200)["errors"])["message"] =~ "not found"
|
||||||
|
|
||||||
|
query = """
|
||||||
|
{
|
||||||
|
event(uuid: "#{event_uuid}") {
|
||||||
|
uuid,
|
||||||
|
draft
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> get("/api", AbsintheHelpers.query_skeleton(query, "event"))
|
||||||
|
|
||||||
|
assert json_response(res, 200)["errors"] == nil
|
||||||
|
assert json_response(res, 200)["data"]["event"]["draft"] == true
|
||||||
|
|
||||||
|
query = """
|
||||||
|
{
|
||||||
|
person(preferredUsername: "#{actor.preferred_username}") {
|
||||||
|
id,
|
||||||
|
participations(eventId: #{event_id}) {
|
||||||
|
id,
|
||||||
|
role,
|
||||||
|
actor {
|
||||||
|
id
|
||||||
|
},
|
||||||
|
event {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
|
||||||
|
|
||||||
|
assert json_response(res, 200)["errors"] == nil
|
||||||
|
assert json_response(res, 200)["data"]["person"]["participations"] == []
|
||||||
|
end
|
||||||
|
|
||||||
test "create_event/3 creates an event with options", %{conn: conn, actor: actor, user: user} do
|
test "create_event/3 creates an event with options", %{conn: conn, actor: actor, user: user} do
|
||||||
begins_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
|
begins_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
|
||||||
ends_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
|
ends_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
|
||||||
@ -684,6 +775,157 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
|
|||||||
"picture for my event"
|
"picture for my event"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "update_event/3 respects the draft status", %{conn: conn, actor: actor, user: user} do
|
||||||
|
event = insert(:event, organizer_actor: actor, draft: true)
|
||||||
|
|
||||||
|
mutation = """
|
||||||
|
mutation {
|
||||||
|
updateEvent(
|
||||||
|
event_id: #{event.id},
|
||||||
|
title: "my event updated but still draft"
|
||||||
|
) {
|
||||||
|
draft,
|
||||||
|
title,
|
||||||
|
uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
|
||||||
|
|
||||||
|
assert json_response(res, 200)["data"]["updateEvent"]["draft"] == true
|
||||||
|
|
||||||
|
query = """
|
||||||
|
{
|
||||||
|
event(uuid: "#{event.uuid}") {
|
||||||
|
uuid,
|
||||||
|
draft
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> get("/api", AbsintheHelpers.query_skeleton(query, "event"))
|
||||||
|
|
||||||
|
assert hd(json_response(res, 200)["errors"])["message"] =~ "not found"
|
||||||
|
|
||||||
|
query = """
|
||||||
|
{
|
||||||
|
event(uuid: "#{event.uuid}") {
|
||||||
|
uuid,
|
||||||
|
draft
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> get("/api", AbsintheHelpers.query_skeleton(query, "event"))
|
||||||
|
|
||||||
|
assert json_response(res, 200)["errors"] == nil
|
||||||
|
assert json_response(res, 200)["data"]["event"]["draft"] == true
|
||||||
|
|
||||||
|
query = """
|
||||||
|
{
|
||||||
|
person(preferredUsername: "#{actor.preferred_username}") {
|
||||||
|
id,
|
||||||
|
participations(eventId: #{event.id}) {
|
||||||
|
id,
|
||||||
|
role,
|
||||||
|
actor {
|
||||||
|
id
|
||||||
|
},
|
||||||
|
event {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
|
||||||
|
|
||||||
|
assert json_response(res, 200)["errors"] == nil
|
||||||
|
assert json_response(res, 200)["data"]["person"]["participations"] == []
|
||||||
|
|
||||||
|
mutation = """
|
||||||
|
mutation {
|
||||||
|
updateEvent(
|
||||||
|
event_id: #{event.id},
|
||||||
|
title: "my event updated and no longer draft",
|
||||||
|
draft: false
|
||||||
|
) {
|
||||||
|
draft,
|
||||||
|
title,
|
||||||
|
uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
|
||||||
|
|
||||||
|
assert json_response(res, 200)["data"]["updateEvent"]["draft"] == false
|
||||||
|
|
||||||
|
query = """
|
||||||
|
{
|
||||||
|
event(uuid: "#{event.uuid}") {
|
||||||
|
uuid,
|
||||||
|
draft
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> get("/api", AbsintheHelpers.query_skeleton(query, "event"))
|
||||||
|
|
||||||
|
assert json_response(res, 200)["errors"] == nil
|
||||||
|
assert json_response(res, 200)["data"]["event"]["draft"] == false
|
||||||
|
|
||||||
|
query = """
|
||||||
|
{
|
||||||
|
person(preferredUsername: "#{actor.preferred_username}") {
|
||||||
|
id,
|
||||||
|
participations(eventId: #{event.id}) {
|
||||||
|
role,
|
||||||
|
actor {
|
||||||
|
id
|
||||||
|
},
|
||||||
|
event {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
|
||||||
|
|
||||||
|
assert json_response(res, 200)["errors"] == nil
|
||||||
|
|
||||||
|
assert json_response(res, 200)["data"]["person"]["participations"] == [
|
||||||
|
%{
|
||||||
|
"actor" => %{"id" => to_string(actor.id)},
|
||||||
|
"event" => %{"id" => to_string(event.id)},
|
||||||
|
"role" => "CREATOR"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
test "list_events/3 returns events", context do
|
test "list_events/3 returns events", context do
|
||||||
event = insert(:event)
|
event = insert(:event)
|
||||||
|
|
||||||
@ -782,6 +1024,24 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
|
|||||||
assert json_response(res, 200)["data"]["events"] |> Enum.map(& &1["uuid"]) == []
|
assert json_response(res, 200)["data"]["events"] |> Enum.map(& &1["uuid"]) == []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "list_events/3 doesn't list draft events", context do
|
||||||
|
insert(:event, visibility: :public, draft: true)
|
||||||
|
|
||||||
|
query = """
|
||||||
|
{
|
||||||
|
events {
|
||||||
|
uuid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
context.conn
|
||||||
|
|> get("/api", AbsintheHelpers.query_skeleton(query, "event"))
|
||||||
|
|
||||||
|
assert json_response(res, 200)["data"]["events"] |> Enum.map(& &1["uuid"]) == []
|
||||||
|
end
|
||||||
|
|
||||||
test "find_event/3 returns an unlisted event", context do
|
test "find_event/3 returns an unlisted event", context do
|
||||||
event = insert(:event, visibility: :unlisted)
|
event = insert(:event, visibility: :unlisted)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user