mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge pull request #6198 from Ocelot-Social-Community/optional-event-parameters
feat(backend): event parameters
This commit is contained in:
commit
738e7ad64c
@ -12,6 +12,7 @@ export const createPostMutation = () => {
|
||||
$categoryIds: [ID]
|
||||
$groupId: ID
|
||||
$postType: PostType
|
||||
$eventInput: _EventInput
|
||||
) {
|
||||
CreatePost(
|
||||
id: $id
|
||||
@ -21,6 +22,7 @@ export const createPostMutation = () => {
|
||||
categoryIds: $categoryIds
|
||||
groupId: $groupId
|
||||
postType: $postType
|
||||
eventInput: $eventInput
|
||||
) {
|
||||
id
|
||||
slug
|
||||
@ -35,6 +37,13 @@ export const createPostMutation = () => {
|
||||
categories {
|
||||
id
|
||||
}
|
||||
eventStart
|
||||
eventLocationName
|
||||
eventVenue
|
||||
eventLocation {
|
||||
lng
|
||||
lat
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
35
backend/src/schema/resolvers/helpers/events.js
Normal file
35
backend/src/schema/resolvers/helpers/events.js
Normal file
@ -0,0 +1,35 @@
|
||||
import { UserInputError } from 'apollo-server'
|
||||
|
||||
export const validateEventParams = (params) => {
|
||||
if (params.postType && params.postType === 'Event') {
|
||||
const { eventInput } = params
|
||||
validateEventDate(eventInput.eventStart)
|
||||
params.eventStart = eventInput.eventStart
|
||||
if (eventInput.eventLocation && !eventInput.eventVenue) {
|
||||
throw new UserInputError('Event venue must be present if event location is given!')
|
||||
}
|
||||
params.eventVenue = eventInput.eventVenue
|
||||
params.eventLocation = eventInput.eventLocation
|
||||
}
|
||||
delete params.eventInput
|
||||
let locationName
|
||||
if (params.eventLocation) {
|
||||
params.eventLocationName = params.eventLocation
|
||||
locationName = params.eventLocation
|
||||
} else {
|
||||
params.eventLocationName = null
|
||||
locationName = null
|
||||
}
|
||||
delete params.eventLocation
|
||||
return locationName
|
||||
}
|
||||
|
||||
const validateEventDate = (dateString) => {
|
||||
const date = new Date(dateString)
|
||||
if (date.toString() === 'Invalid Date')
|
||||
throw new UserInputError('Event start date must be a valid date!')
|
||||
const now = new Date()
|
||||
if (date.getTime() < now.getTime()) {
|
||||
throw new UserInputError('Event start date must be in the future!')
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,8 @@ import Resolver from './helpers/Resolver'
|
||||
import { filterForMutedUsers } from './helpers/filterForMutedUsers'
|
||||
import { filterInvisiblePosts } from './helpers/filterInvisiblePosts'
|
||||
import { filterPostsOfMyGroups } from './helpers/filterPostsOfMyGroups'
|
||||
import { validateEventParams } from './helpers/events'
|
||||
import { createOrUpdateLocations } from './users/location'
|
||||
import CONFIG from '../../config'
|
||||
|
||||
const maintainPinnedPosts = (params) => {
|
||||
@ -81,6 +83,9 @@ export default {
|
||||
CreatePost: async (_parent, params, context, _resolveInfo) => {
|
||||
const { categoryIds, groupId } = params
|
||||
const { image: imageInput } = params
|
||||
|
||||
const locationName = validateEventParams(params)
|
||||
|
||||
delete params.categoryIds
|
||||
delete params.image
|
||||
delete params.groupId
|
||||
@ -143,6 +148,9 @@ export default {
|
||||
})
|
||||
try {
|
||||
const post = await writeTxResultPromise
|
||||
if (locationName) {
|
||||
await createOrUpdateLocations('Post', post.id, locationName, session)
|
||||
}
|
||||
return post
|
||||
} catch (e) {
|
||||
if (e.code === 'Neo.ClientError.Schema.ConstraintValidationFailed')
|
||||
@ -155,6 +163,9 @@ export default {
|
||||
UpdatePost: async (_parent, params, context, _resolveInfo) => {
|
||||
const { categoryIds } = params
|
||||
const { image: imageInput } = params
|
||||
|
||||
const locationName = validateEventParams(params)
|
||||
|
||||
delete params.categoryIds
|
||||
delete params.image
|
||||
const session = context.driver.session()
|
||||
@ -206,6 +217,9 @@ export default {
|
||||
return post
|
||||
})
|
||||
const post = await writeTxResultPromise
|
||||
if (locationName) {
|
||||
await createOrUpdateLocations('Post', post.id, locationName, session)
|
||||
}
|
||||
return post
|
||||
} finally {
|
||||
session.close()
|
||||
@ -392,7 +406,17 @@ export default {
|
||||
},
|
||||
Post: {
|
||||
...Resolver('Post', {
|
||||
undefinedToNull: ['activityId', 'objectId', 'language', 'pinnedAt', 'pinned'],
|
||||
undefinedToNull: [
|
||||
'activityId',
|
||||
'objectId',
|
||||
'language',
|
||||
'pinnedAt',
|
||||
'pinned',
|
||||
'eventVenue',
|
||||
'eventLocation',
|
||||
'eventLocationName',
|
||||
'eventStart',
|
||||
],
|
||||
hasMany: {
|
||||
tags: '-[:TAGGED]->(related:Tag)',
|
||||
categories: '-[:CATEGORIZED]->(related:Category)',
|
||||
@ -405,6 +429,7 @@ export default {
|
||||
pinnedBy: '<-[:PINNED]-(related:User)',
|
||||
image: '-[:HERO_IMAGE]->(related:Image)',
|
||||
group: '-[:IN]->(related:Group)',
|
||||
eventLocation: '-[:IS_IN]->(related:Location)',
|
||||
},
|
||||
count: {
|
||||
commentsCount:
|
||||
|
||||
@ -312,19 +312,6 @@ describe('CreatePost', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('with post type "Event"', () => {
|
||||
it('has label "Event" set', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: { ...variables, postType: 'Event' },
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: { CreatePost: { postType: ['Event'] } },
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with invalid post type', () => {
|
||||
it('throws an error', async () => {
|
||||
await expect(
|
||||
@ -342,6 +329,160 @@ describe('CreatePost', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with post type "Event"', () => {
|
||||
describe('without event start date', () => {
|
||||
it('throws an error', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: {
|
||||
...variables,
|
||||
postType: 'Event',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [
|
||||
{
|
||||
message: "Cannot read properties of undefined (reading 'eventStart')",
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with invalid event start date', () => {
|
||||
it('throws an error', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: {
|
||||
...variables,
|
||||
postType: 'Event',
|
||||
eventInput: {
|
||||
eventStart: 'no date',
|
||||
},
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [
|
||||
{
|
||||
message: 'Event start date must be a valid date!',
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with event start date in the past', () => {
|
||||
it('throws an error', async () => {
|
||||
const now = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: {
|
||||
...variables,
|
||||
postType: 'Event',
|
||||
eventInput: {
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() - 1).toISOString(),
|
||||
},
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [
|
||||
{
|
||||
message: 'Event start date must be in the future!',
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('event location is given but event venue is missing', () => {
|
||||
it('throws an error', async () => {
|
||||
const now = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: {
|
||||
...variables,
|
||||
postType: 'Event',
|
||||
eventInput: {
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() + 1).toISOString(),
|
||||
eventLocation: 'Berlin',
|
||||
},
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [
|
||||
{
|
||||
message: 'Event venue must be present if event location is given!',
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('valid event input without location', () => {
|
||||
it('has label "Event" set', async () => {
|
||||
const now = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: {
|
||||
...variables,
|
||||
postType: 'Event',
|
||||
eventInput: {
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() + 1).toISOString(),
|
||||
},
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
CreatePost: {
|
||||
postType: ['Event'],
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() + 1).toISOString(),
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('valid event input with location', () => {
|
||||
it('has label "Event" set', async () => {
|
||||
const now = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: {
|
||||
...variables,
|
||||
postType: 'Event',
|
||||
eventInput: {
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() + 1).toISOString(),
|
||||
eventLocation: 'Leipzig',
|
||||
eventVenue: 'Connewitzer Kreuz',
|
||||
},
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
CreatePost: {
|
||||
postType: ['Event'],
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() + 1).toISOString(),
|
||||
eventLocationName: 'Leipzig',
|
||||
eventVenue: 'Connewitzer Kreuz',
|
||||
eventLocation: {
|
||||
lng: 12.374733,
|
||||
lat: 51.340632,
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -355,6 +496,7 @@ describe('UpdatePost', () => {
|
||||
$image: ImageInput
|
||||
$categoryIds: [ID]
|
||||
$postType: PostType
|
||||
$eventInput: _EventInput
|
||||
) {
|
||||
UpdatePost(
|
||||
id: $id
|
||||
@ -363,6 +505,7 @@ describe('UpdatePost', () => {
|
||||
image: $image
|
||||
categoryIds: $categoryIds
|
||||
postType: $postType
|
||||
eventInput: $eventInput
|
||||
) {
|
||||
id
|
||||
title
|
||||
@ -377,6 +520,13 @@ describe('UpdatePost', () => {
|
||||
id
|
||||
}
|
||||
postType
|
||||
eventStart
|
||||
eventLocationName
|
||||
eventVenue
|
||||
eventLocation {
|
||||
lng
|
||||
lat
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -498,18 +648,153 @@ describe('UpdatePost', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('post type', () => {
|
||||
it('changes the post type', async () => {
|
||||
await expect(
|
||||
mutate({ mutation: updatePostMutation, variables: { ...variables, postType: 'Event' } }),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
UpdatePost: {
|
||||
id: newlyCreatedPost.id,
|
||||
postType: ['Event'],
|
||||
describe('change post type to event', () => {
|
||||
describe('with missing event start date', () => {
|
||||
it('throws an error', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updatePostMutation,
|
||||
variables: { ...variables, postType: 'Event' },
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [
|
||||
{
|
||||
message: "Cannot read properties of undefined (reading 'eventStart')",
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with invalid event start date', () => {
|
||||
it('throws an error', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updatePostMutation,
|
||||
variables: {
|
||||
...variables,
|
||||
postType: 'Event',
|
||||
eventInput: {
|
||||
eventStart: 'no-date',
|
||||
},
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [
|
||||
{
|
||||
message: 'Event start date must be a valid date!',
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with event start date in the past', () => {
|
||||
it('throws an error', async () => {
|
||||
const now = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updatePostMutation,
|
||||
variables: {
|
||||
...variables,
|
||||
postType: 'Event',
|
||||
eventInput: {
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() - 1).toISOString(),
|
||||
},
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [
|
||||
{
|
||||
message: 'Event start date must be in the future!',
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('event location is given but event venue is missing', () => {
|
||||
it('throws an error', async () => {
|
||||
const now = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updatePostMutation,
|
||||
variables: {
|
||||
...variables,
|
||||
postType: 'Event',
|
||||
eventInput: {
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() + 1).toISOString(),
|
||||
eventLocation: 'Berlin',
|
||||
},
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
errors: [
|
||||
{
|
||||
message: 'Event venue must be present if event location is given!',
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('valid event input without location', () => {
|
||||
it('has label "Event" set', async () => {
|
||||
const now = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updatePostMutation,
|
||||
variables: {
|
||||
...variables,
|
||||
postType: 'Event',
|
||||
eventInput: {
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() + 1).toISOString(),
|
||||
},
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
UpdatePost: {
|
||||
postType: ['Event'],
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() + 1).toISOString(),
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('valid event input with location', () => {
|
||||
it('has label "Event" set', async () => {
|
||||
const now = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updatePostMutation,
|
||||
variables: {
|
||||
...variables,
|
||||
postType: 'Event',
|
||||
eventInput: {
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() + 1).toISOString(),
|
||||
eventLocation: 'Leipzig',
|
||||
eventVenue: 'Connewitzer Kreuz',
|
||||
},
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
UpdatePost: {
|
||||
postType: ['Event'],
|
||||
eventStart: new Date(now.getFullYear(), now.getMonth() + 1).toISOString(),
|
||||
eventLocationName: 'Leipzig',
|
||||
eventVenue: 'Connewitzer Kreuz',
|
||||
eventLocation: {
|
||||
lng: 12.374733,
|
||||
lat: 51.340632,
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -171,14 +171,26 @@ type Post {
|
||||
@cypher(statement: "MATCH (this)<-[emoted:EMOTED]-(:User) RETURN COUNT(DISTINCT emoted)")
|
||||
|
||||
group: Group @relation(name: "IN", direction: "OUT")
|
||||
|
||||
postType: [PostType]
|
||||
@cypher(statement: "RETURN filter(l IN labels(this) WHERE NOT l = 'Post')")
|
||||
|
||||
eventLocationName: String
|
||||
eventLocation: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l")
|
||||
eventVenue: String
|
||||
eventStart: String
|
||||
}
|
||||
|
||||
input _PostInput {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
input _EventInput {
|
||||
eventStart: String!
|
||||
eventLocation: String
|
||||
eventVenue: String
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
CreatePost(
|
||||
id: ID
|
||||
@ -192,6 +204,7 @@ type Mutation {
|
||||
contentExcerpt: String
|
||||
groupId: ID
|
||||
postType: PostType = Article
|
||||
eventInput: _EventInput
|
||||
): Post
|
||||
UpdatePost(
|
||||
id: ID!
|
||||
@ -204,6 +217,7 @@ type Mutation {
|
||||
language: String
|
||||
categoryIds: [ID]
|
||||
postType: PostType
|
||||
eventInput: _EventInput
|
||||
): Post
|
||||
DeletePost(id: ID!): Post
|
||||
AddPostEmotions(to: _PostInput!, data: _EMOTEDInput!): EMOTED
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user