mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Merge pull request #919 from Human-Connection/778-categories-for-posts
Post with categories
This commit is contained in:
commit
7fa3cc7709
@ -88,21 +88,26 @@ describe('currentUser { notifications }', () => {
|
|||||||
describe('who mentions me again', () => {
|
describe('who mentions me again', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const updatedContent = `${post.content} One more mention to <a href="/profile/you" class="mention">@al-capone</a>`
|
const updatedContent = `${post.content} One more mention to <a href="/profile/you" class="mention">@al-capone</a>`
|
||||||
|
const updatedTitle = 'this post has been updated'
|
||||||
// The response `post.content` contains a link but the XSSmiddleware
|
// The response `post.content` contains a link but the XSSmiddleware
|
||||||
// should have the `mention` CSS class removed. I discovered this
|
// should have the `mention` CSS class removed. I discovered this
|
||||||
// during development and thought: A feature not a bug! This way we
|
// during development and thought: A feature not a bug! This way we
|
||||||
// can encode a re-mentioning of users when you edit your post or
|
// can encode a re-mentioning of users when you edit your post or
|
||||||
// comment.
|
// comment.
|
||||||
const createPostMutation = `
|
const updatePostMutation = `
|
||||||
mutation($id: ID!, $content: String!) {
|
mutation($id: ID!, $title: String!, $content: String!) {
|
||||||
UpdatePost(id: $id, content: $content) {
|
UpdatePost(id: $id, title: $title, content: $content) {
|
||||||
title
|
title
|
||||||
content
|
content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
authorClient = new GraphQLClient(host, { headers: authorHeaders })
|
authorClient = new GraphQLClient(host, { headers: authorHeaders })
|
||||||
await authorClient.request(createPostMutation, { id: post.id, content: updatedContent })
|
await authorClient.request(updatePostMutation, {
|
||||||
|
id: post.id,
|
||||||
|
content: updatedContent,
|
||||||
|
title: updatedTitle,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('creates exactly one more notification', async () => {
|
it('creates exactly one more notification', async () => {
|
||||||
|
|||||||
@ -105,7 +105,7 @@ const permissions = shield(
|
|||||||
Query: {
|
Query: {
|
||||||
'*': deny,
|
'*': deny,
|
||||||
findPosts: allow,
|
findPosts: allow,
|
||||||
Category: isAdmin,
|
Category: allow,
|
||||||
Tag: isAdmin,
|
Tag: isAdmin,
|
||||||
Report: isModerator,
|
Report: isModerator,
|
||||||
Notification: isAdmin,
|
Notification: isAdmin,
|
||||||
|
|||||||
@ -17,6 +17,10 @@ export default {
|
|||||||
args.slug = args.slug || (await uniqueSlug(args.title, isUniqueFor(context, 'Post')))
|
args.slug = args.slug || (await uniqueSlug(args.title, isUniqueFor(context, 'Post')))
|
||||||
return resolve(root, args, context, info)
|
return resolve(root, args, context, info)
|
||||||
},
|
},
|
||||||
|
UpdatePost: async (resolve, root, args, context, info) => {
|
||||||
|
args.slug = args.slug || (await uniqueSlug(args.title, isUniqueFor(context, 'Post')))
|
||||||
|
return resolve(root, args, context, info)
|
||||||
|
},
|
||||||
CreateUser: async (resolve, root, args, context, info) => {
|
CreateUser: async (resolve, root, args, context, info) => {
|
||||||
args.slug = args.slug || (await uniqueSlug(args.name, isUniqueFor(context, 'User')))
|
args.slug = args.slug || (await uniqueSlug(args.name, isUniqueFor(context, 'User')))
|
||||||
return resolve(root, args, context, info)
|
return resolve(root, args, context, info)
|
||||||
|
|||||||
@ -18,9 +18,6 @@ export default {
|
|||||||
if (!params.content || content.length < COMMENT_MIN_LENGTH) {
|
if (!params.content || content.length < COMMENT_MIN_LENGTH) {
|
||||||
throw new UserInputError(`Comment must be at least ${COMMENT_MIN_LENGTH} character long!`)
|
throw new UserInputError(`Comment must be at least ${COMMENT_MIN_LENGTH} character long!`)
|
||||||
}
|
}
|
||||||
if (!postId.trim()) {
|
|
||||||
throw new UserInputError(NO_POST_ERR_MESSAGE)
|
|
||||||
}
|
|
||||||
|
|
||||||
const session = context.driver.session()
|
const session = context.driver.session()
|
||||||
const postQueryRes = await session.run(
|
const postQueryRes = await session.run(
|
||||||
|
|||||||
@ -23,7 +23,7 @@ afterEach(async () => {
|
|||||||
|
|
||||||
describe('CreateComment', () => {
|
describe('CreateComment', () => {
|
||||||
const createCommentMutation = gql`
|
const createCommentMutation = gql`
|
||||||
mutation($postId: ID, $content: String!) {
|
mutation($postId: ID!, $content: String!) {
|
||||||
CreateComment(postId: $postId, content: $content) {
|
CreateComment(postId: $postId, content: $content) {
|
||||||
id
|
id
|
||||||
content
|
content
|
||||||
@ -37,13 +37,6 @@ describe('CreateComment', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
const commentQueryForPostId = gql`
|
|
||||||
query($content: String) {
|
|
||||||
Comment(content: $content) {
|
|
||||||
postId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
describe('unauthenticated', () => {
|
describe('unauthenticated', () => {
|
||||||
it('throws authorization error', async () => {
|
it('throws authorization error', async () => {
|
||||||
createCommentVariables = {
|
createCommentVariables = {
|
||||||
@ -191,23 +184,6 @@ describe('CreateComment', () => {
|
|||||||
client.request(createCommentMutation, createCommentVariablesWithNonExistentPost),
|
client.request(createCommentMutation, createCommentVariablesWithNonExistentPost),
|
||||||
).rejects.toThrow('Comment cannot be created without a post!')
|
).rejects.toThrow('Comment cannot be created without a post!')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does not create the comment with the postId as an attribute', async () => {
|
|
||||||
const commentQueryVariablesByContent = {
|
|
||||||
content: "I'm authorised to comment",
|
|
||||||
}
|
|
||||||
|
|
||||||
await client.request(createCommentMutation, createCommentVariables)
|
|
||||||
const { Comment } = await client.request(
|
|
||||||
commentQueryForPostId,
|
|
||||||
commentQueryVariablesByContent,
|
|
||||||
)
|
|
||||||
expect(Comment).toEqual([
|
|
||||||
{
|
|
||||||
postId: null,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -1,30 +1,74 @@
|
|||||||
import { neo4jgraphql } from 'neo4j-graphql-js'
|
import uuid from 'uuid/v4'
|
||||||
import fileUpload from './fileUpload'
|
import fileUpload from './fileUpload'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Mutation: {
|
Mutation: {
|
||||||
UpdatePost: async (object, params, context, resolveInfo) => {
|
UpdatePost: async (object, params, context, resolveInfo) => {
|
||||||
|
const { categoryIds } = params
|
||||||
|
delete params.categoryIds
|
||||||
params = await fileUpload(params, { file: 'imageUpload', url: 'image' })
|
params = await fileUpload(params, { file: 'imageUpload', url: 'image' })
|
||||||
return neo4jgraphql(object, params, context, resolveInfo, false)
|
const session = context.driver.session()
|
||||||
|
const cypherDeletePreviousRelations = `
|
||||||
|
MATCH (post:Post { id: $params.id })-[previousRelations:CATEGORIZED]->(category:Category)
|
||||||
|
DELETE previousRelations
|
||||||
|
RETURN post, category
|
||||||
|
`
|
||||||
|
|
||||||
|
await session.run(cypherDeletePreviousRelations, { params })
|
||||||
|
|
||||||
|
let updatePostCypher = `MATCH (post:Post {id: $params.id})
|
||||||
|
SET post = $params
|
||||||
|
`
|
||||||
|
if (categoryIds && categoryIds.length) {
|
||||||
|
updatePostCypher += `WITH post
|
||||||
|
UNWIND $categoryIds AS categoryId
|
||||||
|
MATCH (category:Category {id: categoryId})
|
||||||
|
MERGE (post)-[:CATEGORIZED]->(category)
|
||||||
|
`
|
||||||
|
}
|
||||||
|
updatePostCypher += `RETURN post`
|
||||||
|
const updatePostVariables = { categoryIds, params }
|
||||||
|
|
||||||
|
const transactionRes = await session.run(updatePostCypher, updatePostVariables)
|
||||||
|
const [post] = transactionRes.records.map(record => {
|
||||||
|
return record.get('post')
|
||||||
|
})
|
||||||
|
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
return post.properties
|
||||||
},
|
},
|
||||||
|
|
||||||
CreatePost: async (object, params, context, resolveInfo) => {
|
CreatePost: async (object, params, context, resolveInfo) => {
|
||||||
|
const { categoryIds } = params
|
||||||
|
delete params.categoryIds
|
||||||
params = await fileUpload(params, { file: 'imageUpload', url: 'image' })
|
params = await fileUpload(params, { file: 'imageUpload', url: 'image' })
|
||||||
const result = await neo4jgraphql(object, params, context, resolveInfo, false)
|
params.id = params.id || uuid()
|
||||||
|
let createPostCypher = `CREATE (post:Post {params})
|
||||||
|
WITH post
|
||||||
|
MATCH (author:User {id: $userId})
|
||||||
|
MERGE (post)<-[:WROTE]-(author)
|
||||||
|
`
|
||||||
|
if (categoryIds) {
|
||||||
|
createPostCypher += `WITH post
|
||||||
|
UNWIND $categoryIds AS categoryId
|
||||||
|
MATCH (category:Category {id: categoryId})
|
||||||
|
MERGE (post)-[:CATEGORIZED]->(category)
|
||||||
|
`
|
||||||
|
}
|
||||||
|
createPostCypher += `RETURN post`
|
||||||
|
const createPostVariables = { userId: context.user.id, categoryIds, params }
|
||||||
|
|
||||||
const session = context.driver.session()
|
const session = context.driver.session()
|
||||||
await session.run(
|
const transactionRes = await session.run(createPostCypher, createPostVariables)
|
||||||
'MATCH (author:User {id: $userId}), (post:Post {id: $postId}) ' +
|
|
||||||
'MERGE (post)<-[:WROTE]-(author) ' +
|
const [post] = transactionRes.records.map(record => {
|
||||||
'RETURN author',
|
return record.get('post')
|
||||||
{
|
})
|
||||||
userId: context.user.id,
|
|
||||||
postId: result.id,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
return result
|
return post.properties
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,34 @@ import { host, login } from '../../jest/helpers'
|
|||||||
|
|
||||||
const factory = Factory()
|
const factory = Factory()
|
||||||
let client
|
let client
|
||||||
|
const postTitle = 'I am a title'
|
||||||
|
const postContent = 'Some content'
|
||||||
|
const oldTitle = 'Old title'
|
||||||
|
const oldContent = 'Old content'
|
||||||
|
const newTitle = 'New title'
|
||||||
|
const newContent = 'New content'
|
||||||
|
const createPostVariables = { title: postTitle, content: postContent }
|
||||||
|
const createPostWithCategoriesMutation = `
|
||||||
|
mutation($title: String!, $content: String!, $categoryIds: [ID]) {
|
||||||
|
CreatePost(title: $title, content: $content, categoryIds: $categoryIds) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
const creatPostWithCategoriesVariables = {
|
||||||
|
title: postTitle,
|
||||||
|
content: postContent,
|
||||||
|
categoryIds: ['cat9', 'cat4', 'cat15'],
|
||||||
|
}
|
||||||
|
const postQueryWithCategories = `
|
||||||
|
query($id: ID) {
|
||||||
|
Post(id: $id) {
|
||||||
|
categories {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await factory.create('User', {
|
await factory.create('User', {
|
||||||
email: 'test@example.org',
|
email: 'test@example.org',
|
||||||
@ -18,8 +45,8 @@ afterEach(async () => {
|
|||||||
|
|
||||||
describe('CreatePost', () => {
|
describe('CreatePost', () => {
|
||||||
const mutation = `
|
const mutation = `
|
||||||
mutation {
|
mutation($title: String!, $content: String!) {
|
||||||
CreatePost(title: "I am a title", content: "Some content") {
|
CreatePost(title: $title, content: $content) {
|
||||||
title
|
title
|
||||||
content
|
content
|
||||||
slug
|
slug
|
||||||
@ -32,7 +59,7 @@ describe('CreatePost', () => {
|
|||||||
describe('unauthenticated', () => {
|
describe('unauthenticated', () => {
|
||||||
it('throws authorization error', async () => {
|
it('throws authorization error', async () => {
|
||||||
client = new GraphQLClient(host)
|
client = new GraphQLClient(host)
|
||||||
await expect(client.request(mutation)).rejects.toThrow('Not Authorised')
|
await expect(client.request(mutation, createPostVariables)).rejects.toThrow('Not Authorised')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -46,15 +73,15 @@ describe('CreatePost', () => {
|
|||||||
it('creates a post', async () => {
|
it('creates a post', async () => {
|
||||||
const expected = {
|
const expected = {
|
||||||
CreatePost: {
|
CreatePost: {
|
||||||
title: 'I am a title',
|
title: postTitle,
|
||||||
content: 'Some content',
|
content: postContent,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
await expect(client.request(mutation)).resolves.toMatchObject(expected)
|
await expect(client.request(mutation, createPostVariables)).resolves.toMatchObject(expected)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('assigns the authenticated user as author', async () => {
|
it('assigns the authenticated user as author', async () => {
|
||||||
await client.request(mutation)
|
await client.request(mutation, createPostVariables)
|
||||||
const { User } = await client.request(
|
const { User } = await client.request(
|
||||||
`{
|
`{
|
||||||
User(email:"test@example.org") {
|
User(email:"test@example.org") {
|
||||||
@ -65,49 +92,75 @@ describe('CreatePost', () => {
|
|||||||
}`,
|
}`,
|
||||||
{ headers },
|
{ headers },
|
||||||
)
|
)
|
||||||
expect(User).toEqual([{ contributions: [{ title: 'I am a title' }] }])
|
expect(User).toEqual([{ contributions: [{ title: postTitle }] }])
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('disabled and deleted', () => {
|
describe('disabled and deleted', () => {
|
||||||
it('initially false', async () => {
|
it('initially false', async () => {
|
||||||
const expected = { CreatePost: { disabled: false, deleted: false } }
|
const expected = { CreatePost: { disabled: false, deleted: false } }
|
||||||
await expect(client.request(mutation)).resolves.toMatchObject(expected)
|
await expect(client.request(mutation, createPostVariables)).resolves.toMatchObject(expected)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('language', () => {
|
describe('language', () => {
|
||||||
it('allows a user to set the language of the post', async () => {
|
it('allows a user to set the language of the post', async () => {
|
||||||
const createPostWithLanguageMutation = `
|
const createPostWithLanguageMutation = `
|
||||||
mutation {
|
mutation($title: String!, $content: String!, $language: String) {
|
||||||
CreatePost(title: "I am a title", content: "Some content", language: "en") {
|
CreatePost(title: $title, content: $content, language: $language) {
|
||||||
language
|
language
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
const createPostWithLanguageVariables = {
|
||||||
|
title: postTitle,
|
||||||
|
content: postContent,
|
||||||
|
language: 'en',
|
||||||
|
}
|
||||||
const expected = { CreatePost: { language: 'en' } }
|
const expected = { CreatePost: { language: 'en' } }
|
||||||
await expect(client.request(createPostWithLanguageMutation)).resolves.toEqual(
|
await expect(
|
||||||
expect.objectContaining(expected),
|
client.request(createPostWithLanguageMutation, createPostWithLanguageVariables),
|
||||||
|
).resolves.toEqual(expect.objectContaining(expected))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('categories', () => {
|
||||||
|
it('allows a user to set the categories of the post', async () => {
|
||||||
|
await Promise.all([
|
||||||
|
factory.create('Category', {
|
||||||
|
id: 'cat9',
|
||||||
|
name: 'Democracy & Politics',
|
||||||
|
icon: 'university',
|
||||||
|
}),
|
||||||
|
factory.create('Category', {
|
||||||
|
id: 'cat4',
|
||||||
|
name: 'Environment & Nature',
|
||||||
|
icon: 'tree',
|
||||||
|
}),
|
||||||
|
factory.create('Category', {
|
||||||
|
id: 'cat15',
|
||||||
|
name: 'Consumption & Sustainability',
|
||||||
|
icon: 'shopping-cart',
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
const expected = [{ id: 'cat9' }, { id: 'cat4' }, { id: 'cat15' }]
|
||||||
|
const postWithCategories = await client.request(
|
||||||
|
createPostWithCategoriesMutation,
|
||||||
|
creatPostWithCategoriesVariables,
|
||||||
)
|
)
|
||||||
|
const postQueryWithCategoriesVariables = {
|
||||||
|
id: postWithCategories.CreatePost.id,
|
||||||
|
}
|
||||||
|
await expect(
|
||||||
|
client.request(postQueryWithCategories, postQueryWithCategoriesVariables),
|
||||||
|
).resolves.toEqual({ Post: [{ categories: expect.arrayContaining(expected) }] })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('UpdatePost', () => {
|
describe('UpdatePost', () => {
|
||||||
const mutation = `
|
let updatePostMutation
|
||||||
mutation($id: ID!, $content: String) {
|
let updatePostVariables
|
||||||
UpdatePost(id: $id, content: $content) {
|
|
||||||
id
|
|
||||||
content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
let variables = {
|
|
||||||
id: 'p1',
|
|
||||||
content: 'New content',
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const asAuthor = Factory()
|
const asAuthor = Factory()
|
||||||
await asAuthor.create('User', {
|
await asAuthor.create('User', {
|
||||||
@ -120,14 +173,32 @@ describe('UpdatePost', () => {
|
|||||||
})
|
})
|
||||||
await asAuthor.create('Post', {
|
await asAuthor.create('Post', {
|
||||||
id: 'p1',
|
id: 'p1',
|
||||||
content: 'Old content',
|
title: oldTitle,
|
||||||
|
content: oldContent,
|
||||||
})
|
})
|
||||||
|
updatePostMutation = `
|
||||||
|
mutation($id: ID!, $title: String!, $content: String!, $categoryIds: [ID]) {
|
||||||
|
UpdatePost(id: $id, title: $title, content: $content, categoryIds: $categoryIds) {
|
||||||
|
id
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
updatePostVariables = {
|
||||||
|
id: 'p1',
|
||||||
|
title: newTitle,
|
||||||
|
content: newContent,
|
||||||
|
categoryIds: null,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('unauthenticated', () => {
|
describe('unauthenticated', () => {
|
||||||
it('throws authorization error', async () => {
|
it('throws authorization error', async () => {
|
||||||
client = new GraphQLClient(host)
|
client = new GraphQLClient(host)
|
||||||
await expect(client.request(mutation, variables)).rejects.toThrow('Not Authorised')
|
await expect(client.request(updatePostMutation, updatePostVariables)).rejects.toThrow(
|
||||||
|
'Not Authorised',
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -139,7 +210,9 @@ describe('UpdatePost', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('throws authorization error', async () => {
|
it('throws authorization error', async () => {
|
||||||
await expect(client.request(mutation, variables)).rejects.toThrow('Not Authorised')
|
await expect(client.request(updatePostMutation, updatePostVariables)).rejects.toThrow(
|
||||||
|
'Not Authorised',
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -151,8 +224,59 @@ describe('UpdatePost', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('updates a post', async () => {
|
it('updates a post', async () => {
|
||||||
const expected = { UpdatePost: { id: 'p1', content: 'New content' } }
|
const expected = { UpdatePost: { id: 'p1', content: newContent } }
|
||||||
await expect(client.request(mutation, variables)).resolves.toEqual(expected)
|
await expect(client.request(updatePostMutation, updatePostVariables)).resolves.toEqual(
|
||||||
|
expected,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('categories', () => {
|
||||||
|
let postWithCategories
|
||||||
|
beforeEach(async () => {
|
||||||
|
await Promise.all([
|
||||||
|
factory.create('Category', {
|
||||||
|
id: 'cat9',
|
||||||
|
name: 'Democracy & Politics',
|
||||||
|
icon: 'university',
|
||||||
|
}),
|
||||||
|
factory.create('Category', {
|
||||||
|
id: 'cat4',
|
||||||
|
name: 'Environment & Nature',
|
||||||
|
icon: 'tree',
|
||||||
|
}),
|
||||||
|
factory.create('Category', {
|
||||||
|
id: 'cat15',
|
||||||
|
name: 'Consumption & Sustainability',
|
||||||
|
icon: 'shopping-cart',
|
||||||
|
}),
|
||||||
|
factory.create('Category', {
|
||||||
|
id: 'cat27',
|
||||||
|
name: 'Animal Protection',
|
||||||
|
icon: 'paw',
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
postWithCategories = await client.request(
|
||||||
|
createPostWithCategoriesMutation,
|
||||||
|
creatPostWithCategoriesVariables,
|
||||||
|
)
|
||||||
|
updatePostVariables = {
|
||||||
|
id: postWithCategories.CreatePost.id,
|
||||||
|
title: newTitle,
|
||||||
|
content: newContent,
|
||||||
|
categoryIds: ['cat27'],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows a user to update the categories of a post', async () => {
|
||||||
|
await client.request(updatePostMutation, updatePostVariables)
|
||||||
|
const expected = [{ id: 'cat27' }]
|
||||||
|
const postQueryWithCategoriesVariables = {
|
||||||
|
id: postWithCategories.CreatePost.id,
|
||||||
|
}
|
||||||
|
await expect(
|
||||||
|
client.request(postQueryWithCategories, postQueryWithCategoriesVariables),
|
||||||
|
).resolves.toEqual({ Post: [{ categories: expect.arrayContaining(expected) }] })
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
type Comment {
|
type Comment {
|
||||||
id: ID!
|
id: ID!
|
||||||
activityId: String
|
activityId: String
|
||||||
postId: ID
|
|
||||||
author: User @relation(name: "WROTE", direction: "IN")
|
author: User @relation(name: "WROTE", direction: "IN")
|
||||||
content: String!
|
content: String!
|
||||||
contentExcerpt: String
|
contentExcerpt: String
|
||||||
@ -11,4 +10,24 @@ type Comment {
|
|||||||
deleted: Boolean
|
deleted: Boolean
|
||||||
disabled: Boolean
|
disabled: Boolean
|
||||||
disabledBy: User @relation(name: "DISABLED", direction: "IN")
|
disabledBy: User @relation(name: "DISABLED", direction: "IN")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
CreateComment(
|
||||||
|
id: ID
|
||||||
|
postId: ID!
|
||||||
|
content: String!
|
||||||
|
contentExcerpt: String
|
||||||
|
deleted: Boolean
|
||||||
|
disabled: Boolean
|
||||||
|
createdAt: String
|
||||||
|
): Comment
|
||||||
|
UpdateComment(
|
||||||
|
id: ID!
|
||||||
|
content: String
|
||||||
|
contentExcerpt: String
|
||||||
|
deleted: Boolean
|
||||||
|
disabled: Boolean
|
||||||
|
): Comment
|
||||||
|
DeleteComment(id: ID!): Comment
|
||||||
|
}
|
||||||
|
|||||||
@ -49,3 +49,42 @@ type Post {
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
CreatePost(
|
||||||
|
id: ID
|
||||||
|
activityId: String
|
||||||
|
objectId: String
|
||||||
|
title: String!
|
||||||
|
slug: String
|
||||||
|
content: String!
|
||||||
|
image: String
|
||||||
|
imageUpload: Upload
|
||||||
|
visibility: Visibility
|
||||||
|
deleted: Boolean
|
||||||
|
disabled: Boolean
|
||||||
|
createdAt: String
|
||||||
|
updatedAt: String
|
||||||
|
language: String
|
||||||
|
categoryIds: [ID]
|
||||||
|
contentExcerpt: String
|
||||||
|
): Post
|
||||||
|
UpdatePost(
|
||||||
|
id: ID!
|
||||||
|
activityId: String
|
||||||
|
objectId: String
|
||||||
|
title: String!
|
||||||
|
slug: String
|
||||||
|
content: String!
|
||||||
|
contentExcerpt: String
|
||||||
|
image: String
|
||||||
|
imageUpload: Upload
|
||||||
|
visibility: Visibility
|
||||||
|
deleted: Boolean
|
||||||
|
disabled: Boolean
|
||||||
|
createdAt: String
|
||||||
|
updatedAt: String
|
||||||
|
language: String
|
||||||
|
categoryIds: [ID]
|
||||||
|
): Post
|
||||||
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ export default function(params) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
mutation: `
|
mutation: `
|
||||||
mutation($id: ID!, $postId: ID, $content: String!) {
|
mutation($id: ID!, $postId: ID!, $content: String!) {
|
||||||
CreateComment(id: $id, postId: $postId, content: $content) {
|
CreateComment(id: $id, postId: $postId, content: $content) {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|||||||
108
webapp/components/CategoriesSelect/CategoriesSelect.spec.js
Normal file
108
webapp/components/CategoriesSelect/CategoriesSelect.spec.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import { mount, createLocalVue } from '@vue/test-utils'
|
||||||
|
import CategoriesSelect from './CategoriesSelect'
|
||||||
|
import Styleguide from '@human-connection/styleguide'
|
||||||
|
|
||||||
|
const localVue = createLocalVue()
|
||||||
|
localVue.use(Styleguide)
|
||||||
|
|
||||||
|
describe('CategoriesSelect.vue', () => {
|
||||||
|
let wrapper
|
||||||
|
let mocks
|
||||||
|
let democracyAndPolitics
|
||||||
|
let environmentAndNature
|
||||||
|
let consumptionAndSustainablity
|
||||||
|
|
||||||
|
const categories = [
|
||||||
|
{
|
||||||
|
id: 'cat9',
|
||||||
|
name: 'Democracy & Politics',
|
||||||
|
icon: 'university',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'cat4',
|
||||||
|
name: 'Environment & Nature',
|
||||||
|
icon: 'tree',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'cat15',
|
||||||
|
name: 'Consumption & Sustainability',
|
||||||
|
icon: 'shopping-cart',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Cooperation & Development',
|
||||||
|
icon: 'users',
|
||||||
|
id: 'cat8',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
beforeEach(() => {
|
||||||
|
mocks = {
|
||||||
|
$t: jest.fn(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('shallowMount', () => {
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(CategoriesSelect, { mocks, localVue })
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('toggleCategory', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper.vm.categories = categories
|
||||||
|
democracyAndPolitics = wrapper.findAll('button').at(0)
|
||||||
|
democracyAndPolitics.trigger('click')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('adds categories to selectedCategoryIds when clicked', () => {
|
||||||
|
expect(wrapper.vm.selectedCategoryIds).toEqual([categories[0].id])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits an updateCategories event when the selectedCategoryIds changes', () => {
|
||||||
|
expect(wrapper.emitted().updateCategories[0][0]).toEqual([categories[0].id])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('removes categories when clicked a second time', () => {
|
||||||
|
democracyAndPolitics.trigger('click')
|
||||||
|
expect(wrapper.vm.selectedCategoryIds).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('changes the selectedCount when selectedCategoryIds is updated', () => {
|
||||||
|
expect(wrapper.vm.selectedCount).toEqual(1)
|
||||||
|
democracyAndPolitics.trigger('click')
|
||||||
|
expect(wrapper.vm.selectedCount).toEqual(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets a category to active when it has been selected', () => {
|
||||||
|
expect(wrapper.vm.isActive(categories[0].id)).toEqual(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('maximum', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
environmentAndNature = wrapper.findAll('button').at(1)
|
||||||
|
consumptionAndSustainablity = wrapper.findAll('button').at(2)
|
||||||
|
environmentAndNature.trigger('click')
|
||||||
|
consumptionAndSustainablity.trigger('click')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows three categories to be selected', () => {
|
||||||
|
expect(wrapper.vm.selectedCategoryIds).toEqual([
|
||||||
|
categories[0].id,
|
||||||
|
categories[1].id,
|
||||||
|
categories[2].id,
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets reachedMaximum to true after three', () => {
|
||||||
|
expect(wrapper.vm.reachedMaximum).toEqual(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets other categories to disabled after three', () => {
|
||||||
|
expect(wrapper.vm.isDisabled(categories[3].id)).toEqual(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
102
webapp/components/CategoriesSelect/CategoriesSelect.vue
Normal file
102
webapp/components/CategoriesSelect/CategoriesSelect.vue
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ds-flex :gutter="{ base: 'xx-small', md: 'small', lg: 'xx-small' }">
|
||||||
|
<div v-for="category in categories" :key="category.id">
|
||||||
|
<ds-flex-item>
|
||||||
|
<ds-button
|
||||||
|
size="small"
|
||||||
|
@click.prevent="toggleCategory(category.id)"
|
||||||
|
:primary="isActive(category.id)"
|
||||||
|
:disabled="isDisabled(category.id)"
|
||||||
|
>
|
||||||
|
<ds-icon :name="category.icon" />
|
||||||
|
{{ category.name }}
|
||||||
|
</ds-button>
|
||||||
|
</ds-flex-item>
|
||||||
|
</div>
|
||||||
|
</ds-flex>
|
||||||
|
<p class="small-info">
|
||||||
|
{{
|
||||||
|
$t('contribution.categories.infoSelectedNoOfMaxCategories', {
|
||||||
|
chosen: selectedCount,
|
||||||
|
max: selectedMax,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
existingCategoryIds: { type: Array, default: () => [] },
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
categories: null,
|
||||||
|
selectedMax: 3,
|
||||||
|
selectedCategoryIds: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
selectedCount() {
|
||||||
|
return this.selectedCategoryIds.length
|
||||||
|
},
|
||||||
|
reachedMaximum() {
|
||||||
|
return this.selectedCount >= this.selectedMax
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selectedCategoryIds(categoryIds) {
|
||||||
|
this.$emit('updateCategories', categoryIds)
|
||||||
|
},
|
||||||
|
existingCategoryIds: {
|
||||||
|
immediate: true,
|
||||||
|
handler: function(existingCategoryIds) {
|
||||||
|
if (!existingCategoryIds || !existingCategoryIds.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.selectedCategoryIds = existingCategoryIds
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleCategory(id) {
|
||||||
|
const index = this.selectedCategoryIds.indexOf(id)
|
||||||
|
if (index > -1) {
|
||||||
|
this.selectedCategoryIds.splice(index, 1)
|
||||||
|
} else {
|
||||||
|
this.selectedCategoryIds.push(id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isActive(id) {
|
||||||
|
const index = this.selectedCategoryIds.indexOf(id)
|
||||||
|
if (index > -1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
isDisabled(id) {
|
||||||
|
return !!(this.reachedMaximum && !this.isActive(id))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
apollo: {
|
||||||
|
Category: {
|
||||||
|
query() {
|
||||||
|
return gql(`{
|
||||||
|
Category {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
icon
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
},
|
||||||
|
result(result) {
|
||||||
|
this.categories = result.data.Category
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -1,8 +1,9 @@
|
|||||||
import { config, mount, createLocalVue } from '@vue/test-utils'
|
import { config, mount, createLocalVue } from '@vue/test-utils'
|
||||||
import ContributionForm from './index.vue'
|
import ContributionForm from './ContributionForm.vue'
|
||||||
import Styleguide from '@human-connection/styleguide'
|
import Styleguide from '@human-connection/styleguide'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import PostMutations from '~/graphql/PostMutations.js'
|
import PostMutations from '~/graphql/PostMutations.js'
|
||||||
|
import CategoriesSelect from '~/components/CategoriesSelect/CategoriesSelect'
|
||||||
import Filters from '~/plugins/vue-filters'
|
import Filters from '~/plugins/vue-filters'
|
||||||
import TeaserImage from '~/components/TeaserImage/TeaserImage'
|
import TeaserImage from '~/components/TeaserImage/TeaserImage'
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ describe('ContributionForm.vue', () => {
|
|||||||
file: { filename: 'avataar.svg', previewElement: '' },
|
file: { filename: 'avataar.svg', previewElement: '' },
|
||||||
url: 'someUrlToImage',
|
url: 'someUrlToImage',
|
||||||
}
|
}
|
||||||
|
const image = '/uploads/1562010976466-avataaars'
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mocks = {
|
mocks = {
|
||||||
$t: jest.fn(),
|
$t: jest.fn(),
|
||||||
@ -112,7 +113,9 @@ describe('ContributionForm.vue', () => {
|
|||||||
content: postContent,
|
content: postContent,
|
||||||
language: 'en',
|
language: 'en',
|
||||||
id: null,
|
id: null,
|
||||||
|
categoryIds: null,
|
||||||
imageUpload: null,
|
imageUpload: null,
|
||||||
|
image: null,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
postTitleInput = wrapper.find('.ds-input')
|
postTitleInput = wrapper.find('.ds-input')
|
||||||
@ -137,6 +140,14 @@ describe('ContributionForm.vue', () => {
|
|||||||
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
|
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('supports adding categories', async () => {
|
||||||
|
const categoryIds = ['cat12', 'cat15', 'cat37']
|
||||||
|
expectedParams.variables.categoryIds = categoryIds
|
||||||
|
wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds)
|
||||||
|
await wrapper.find('form').trigger('submit')
|
||||||
|
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
|
||||||
|
})
|
||||||
|
|
||||||
it('supports adding a teaser image', async () => {
|
it('supports adding a teaser image', async () => {
|
||||||
expectedParams.variables.imageUpload = imageUpload
|
expectedParams.variables.imageUpload = imageUpload
|
||||||
wrapper.find(TeaserImage).vm.$emit('addTeaserImage', imageUpload)
|
wrapper.find(TeaserImage).vm.$emit('addTeaserImage', imageUpload)
|
||||||
@ -189,7 +200,8 @@ describe('ContributionForm.vue', () => {
|
|||||||
title: 'dies ist ein Post',
|
title: 'dies ist ein Post',
|
||||||
content: 'auf Deutsch geschrieben',
|
content: 'auf Deutsch geschrieben',
|
||||||
language: 'de',
|
language: 'de',
|
||||||
imageUpload,
|
image,
|
||||||
|
categories: [{ id: 'cat12', name: 'Democracy & Politics' }],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
@ -219,7 +231,9 @@ describe('ContributionForm.vue', () => {
|
|||||||
content: postContent,
|
content: postContent,
|
||||||
language: propsData.contribution.language,
|
language: propsData.contribution.language,
|
||||||
id: propsData.contribution.id,
|
id: propsData.contribution.id,
|
||||||
imageUpload,
|
categoryIds: ['cat12'],
|
||||||
|
image,
|
||||||
|
imageUpload: null,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
postTitleInput = wrapper.find('.ds-input')
|
postTitleInput = wrapper.find('.ds-input')
|
||||||
@ -228,6 +242,17 @@ describe('ContributionForm.vue', () => {
|
|||||||
await wrapper.find('form').trigger('submit')
|
await wrapper.find('form').trigger('submit')
|
||||||
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
|
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('supports updating categories', async () => {
|
||||||
|
const categoryIds = ['cat3', 'cat51', 'cat37']
|
||||||
|
postTitleInput = wrapper.find('.ds-input')
|
||||||
|
postTitleInput.setValue(postTitle)
|
||||||
|
wrapper.vm.updateEditorContent(postContent)
|
||||||
|
expectedParams.variables.categoryIds = categoryIds
|
||||||
|
wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds)
|
||||||
|
await wrapper.find('form').trigger('submit')
|
||||||
|
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -14,6 +14,11 @@
|
|||||||
<hc-editor :users="users" :value="form.content" @input="updateEditorContent" />
|
<hc-editor :users="users" :value="form.content" @input="updateEditorContent" />
|
||||||
</no-ssr>
|
</no-ssr>
|
||||||
<ds-space margin-bottom="xxx-large" />
|
<ds-space margin-bottom="xxx-large" />
|
||||||
|
<hc-categories-select
|
||||||
|
model="categoryIds"
|
||||||
|
@updateCategories="updateCategories"
|
||||||
|
:existingCategoryIds="form.categoryIds"
|
||||||
|
/>
|
||||||
<ds-flex class="contribution-form-footer">
|
<ds-flex class="contribution-form-footer">
|
||||||
<ds-flex-item :width="{ base: '10%', sm: '10%', md: '10%', lg: '15%' }" />
|
<ds-flex-item :width="{ base: '10%', sm: '10%', md: '10%', lg: '15%' }" />
|
||||||
<ds-flex-item :width="{ base: '80%', sm: '30%', md: '30%', lg: '20%' }">
|
<ds-flex-item :width="{ base: '80%', sm: '30%', md: '30%', lg: '20%' }">
|
||||||
@ -32,7 +37,7 @@
|
|||||||
:disabled="loading || disabled"
|
:disabled="loading || disabled"
|
||||||
ghost
|
ghost
|
||||||
class="cancel-button"
|
class="cancel-button"
|
||||||
@click="$router.back()"
|
@click.prevent="$router.back()"
|
||||||
>
|
>
|
||||||
{{ $t('actions.cancel') }}
|
{{ $t('actions.cancel') }}
|
||||||
</ds-button>
|
</ds-button>
|
||||||
@ -58,11 +63,13 @@ import HcEditor from '~/components/Editor'
|
|||||||
import orderBy from 'lodash/orderBy'
|
import orderBy from 'lodash/orderBy'
|
||||||
import locales from '~/locales'
|
import locales from '~/locales'
|
||||||
import PostMutations from '~/graphql/PostMutations.js'
|
import PostMutations from '~/graphql/PostMutations.js'
|
||||||
|
import HcCategoriesSelect from '~/components/CategoriesSelect/CategoriesSelect'
|
||||||
import HcTeaserImage from '~/components/TeaserImage/TeaserImage'
|
import HcTeaserImage from '~/components/TeaserImage/TeaserImage'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
HcEditor,
|
HcEditor,
|
||||||
|
HcCategoriesSelect,
|
||||||
HcTeaserImage,
|
HcTeaserImage,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
@ -74,8 +81,10 @@ export default {
|
|||||||
title: '',
|
title: '',
|
||||||
content: '',
|
content: '',
|
||||||
teaserImage: null,
|
teaserImage: null,
|
||||||
|
image: null,
|
||||||
language: null,
|
language: null,
|
||||||
languageOptions: [],
|
languageOptions: [],
|
||||||
|
categoryIds: null,
|
||||||
},
|
},
|
||||||
formSchema: {
|
formSchema: {
|
||||||
title: { required: true, min: 3, max: 64 },
|
title: { required: true, min: 3, max: 64 },
|
||||||
@ -99,7 +108,8 @@ export default {
|
|||||||
this.slug = contribution.slug
|
this.slug = contribution.slug
|
||||||
this.form.content = contribution.content
|
this.form.content = contribution.content
|
||||||
this.form.title = contribution.title
|
this.form.title = contribution.title
|
||||||
this.form.teaserImage = contribution.imageUpload
|
this.form.image = contribution.image
|
||||||
|
this.form.categoryIds = this.categoryIds(contribution.categories)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -117,7 +127,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submit() {
|
submit() {
|
||||||
const { title, content, teaserImage } = this.form
|
const { title, content, image, teaserImage, categoryIds } = this.form
|
||||||
let language
|
let language
|
||||||
if (this.form.language) {
|
if (this.form.language) {
|
||||||
language = this.form.language.value
|
language = this.form.language.value
|
||||||
@ -134,7 +144,9 @@ export default {
|
|||||||
id: this.id,
|
id: this.id,
|
||||||
title,
|
title,
|
||||||
content,
|
content,
|
||||||
|
categoryIds,
|
||||||
language,
|
language,
|
||||||
|
image,
|
||||||
imageUpload: teaserImage,
|
imageUpload: teaserImage,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -142,7 +154,6 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
this.$toast.success(this.$t('contribution.success'))
|
this.$toast.success(this.$t('contribution.success'))
|
||||||
this.disabled = true
|
this.disabled = true
|
||||||
|
|
||||||
const result = res.data[this.id ? 'UpdatePost' : 'CreatePost']
|
const result = res.data[this.id ? 'UpdatePost' : 'CreatePost']
|
||||||
|
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
@ -165,9 +176,19 @@ export default {
|
|||||||
this.form.languageOptions.push({ label: locale.name, value: locale.code })
|
this.form.languageOptions.push({ label: locale.name, value: locale.code })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
updateCategories(ids) {
|
||||||
|
this.form.categoryIds = ids
|
||||||
|
},
|
||||||
addTeaserImage(file) {
|
addTeaserImage(file) {
|
||||||
this.form.teaserImage = file
|
this.form.teaserImage = file
|
||||||
},
|
},
|
||||||
|
categoryIds(categories) {
|
||||||
|
let categoryIds = []
|
||||||
|
categories.map(categoryId => {
|
||||||
|
categoryIds.push(categoryId.id)
|
||||||
|
})
|
||||||
|
return categoryIds
|
||||||
|
},
|
||||||
},
|
},
|
||||||
apollo: {
|
apollo: {
|
||||||
User: {
|
User: {
|
||||||
@ -3,7 +3,7 @@ import gql from 'graphql-tag'
|
|||||||
export default () => {
|
export default () => {
|
||||||
return {
|
return {
|
||||||
CreateComment: gql`
|
CreateComment: gql`
|
||||||
mutation($postId: ID, $content: String!) {
|
mutation($postId: ID!, $content: String!) {
|
||||||
CreateComment(postId: $postId, content: $content) {
|
CreateComment(postId: $postId, content: $content) {
|
||||||
id
|
id
|
||||||
contentExcerpt
|
contentExcerpt
|
||||||
|
|||||||
@ -3,20 +3,25 @@ import gql from 'graphql-tag'
|
|||||||
export default () => {
|
export default () => {
|
||||||
return {
|
return {
|
||||||
CreatePost: gql`
|
CreatePost: gql`
|
||||||
mutation($title: String!, $content: String!, $language: String, $imageUpload: Upload) {
|
mutation(
|
||||||
|
$title: String!
|
||||||
|
$content: String!
|
||||||
|
$language: String
|
||||||
|
$categoryIds: [ID]
|
||||||
|
$imageUpload: Upload
|
||||||
|
) {
|
||||||
CreatePost(
|
CreatePost(
|
||||||
title: $title
|
title: $title
|
||||||
content: $content
|
content: $content
|
||||||
language: $language
|
language: $language
|
||||||
|
categoryIds: $categoryIds
|
||||||
imageUpload: $imageUpload
|
imageUpload: $imageUpload
|
||||||
) {
|
) {
|
||||||
id
|
|
||||||
title
|
title
|
||||||
slug
|
slug
|
||||||
content
|
content
|
||||||
contentExcerpt
|
contentExcerpt
|
||||||
language
|
language
|
||||||
imageUpload
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@ -27,6 +32,8 @@ export default () => {
|
|||||||
$content: String!
|
$content: String!
|
||||||
$language: String
|
$language: String
|
||||||
$imageUpload: Upload
|
$imageUpload: Upload
|
||||||
|
$categoryIds: [ID]
|
||||||
|
$image: String
|
||||||
) {
|
) {
|
||||||
UpdatePost(
|
UpdatePost(
|
||||||
id: $id
|
id: $id
|
||||||
@ -34,6 +41,8 @@ export default () => {
|
|||||||
content: $content
|
content: $content
|
||||||
language: $language
|
language: $language
|
||||||
imageUpload: $imageUpload
|
imageUpload: $imageUpload
|
||||||
|
categoryIds: $categoryIds
|
||||||
|
image: $image
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
@ -41,7 +50,7 @@ export default () => {
|
|||||||
content
|
content
|
||||||
contentExcerpt
|
contentExcerpt
|
||||||
language
|
language
|
||||||
imageUpload
|
image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
|||||||
@ -332,7 +332,10 @@
|
|||||||
"filterFollow": "Beiträge filtern von Usern denen ich folge",
|
"filterFollow": "Beiträge filtern von Usern denen ich folge",
|
||||||
"filterALL": "Alle Beiträge anzeigen",
|
"filterALL": "Alle Beiträge anzeigen",
|
||||||
"success": "Gespeichert!",
|
"success": "Gespeichert!",
|
||||||
"languageSelectLabel": "Sprache"
|
"languageSelectLabel": "Sprache",
|
||||||
|
"categories": {
|
||||||
|
"infoSelectedNoOfMaxCategories": "{chosen} von {max} Kategorien ausgewählt"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -331,6 +331,9 @@
|
|||||||
"filterFollow": "Filter contributions from users I follow",
|
"filterFollow": "Filter contributions from users I follow",
|
||||||
"filterALL": "View all contributions",
|
"filterALL": "View all contributions",
|
||||||
"success": "Saved!",
|
"success": "Saved!",
|
||||||
"languageSelectLabel": "Language"
|
"languageSelectLabel": "Language",
|
||||||
|
"categories": {
|
||||||
|
"infoSelectedNoOfMaxCategories": "{chosen} of {max} categories selected"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import HcContributionForm from '~/components/ContributionForm'
|
import HcContributionForm from '~/components/ContributionForm/ContributionForm'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import HcContributionForm from '~/components/ContributionForm'
|
import HcContributionForm from '~/components/ContributionForm/ContributionForm'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user