mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge pull request #536 from Human-Connection/352-add-authorship-to-comments
Add authorship to comments at creation
This commit is contained in:
commit
b8cecd7fe3
@ -2,44 +2,47 @@ import { neo4jgraphql } from 'neo4j-graphql-js'
|
||||
import { UserInputError } from 'apollo-server'
|
||||
|
||||
const COMMENT_MIN_LENGTH = 1
|
||||
const NO_POST_ERR_MESSAGE = 'Comment cannot be created without a post!'
|
||||
|
||||
export default {
|
||||
Query: {
|
||||
CommentByPost: async (object, params, context, resolveInfo) => {
|
||||
const { postId } = params
|
||||
|
||||
const session = context.driver.session()
|
||||
const transactionRes = await session.run(`
|
||||
MATCH (comment:Comment)-[:COMMENTS]->(post:Post {id: $postId})
|
||||
RETURN comment {.id, .contentExcerpt, .createdAt} ORDER BY comment.createdAt ASC`, {
|
||||
postId
|
||||
})
|
||||
|
||||
session.close()
|
||||
let comments = []
|
||||
transactionRes.records.map(record => {
|
||||
comments.push(record.get('comment'))
|
||||
})
|
||||
|
||||
return comments
|
||||
}
|
||||
},
|
||||
Mutation: {
|
||||
CreateComment: async (object, params, context, resolveInfo) => {
|
||||
const content = params.content.replace(/<(?:.|\n)*?>/gm, '').trim()
|
||||
const { postId } = params
|
||||
// Adding relationship from comment to post by passing in the postId,
|
||||
// but we do not want to create the comment with postId as an attribute
|
||||
// because we use relationships for this. So, we are deleting it from params
|
||||
// before comment creation.
|
||||
delete params.postId
|
||||
|
||||
if (!params.content || content.length < COMMENT_MIN_LENGTH) {
|
||||
throw new UserInputError(`Comment must be at least ${COMMENT_MIN_LENGTH} character long!`)
|
||||
}
|
||||
const { postId } = params
|
||||
delete params.postId
|
||||
const comment = await neo4jgraphql(object, params, context, resolveInfo, false)
|
||||
if (!postId.trim()) {
|
||||
throw new UserInputError(NO_POST_ERR_MESSAGE)
|
||||
}
|
||||
|
||||
const session = context.driver.session()
|
||||
const postQueryRes = await session.run(`
|
||||
MATCH (post:Post {id: $postId})
|
||||
RETURN post`, {
|
||||
postId
|
||||
}
|
||||
)
|
||||
const [post] = postQueryRes.records.map(record => {
|
||||
return record.get('post')
|
||||
})
|
||||
|
||||
if (!post) {
|
||||
throw new UserInputError(NO_POST_ERR_MESSAGE)
|
||||
}
|
||||
const comment = await neo4jgraphql(object, params, context, resolveInfo, false)
|
||||
|
||||
await session.run(`
|
||||
MATCH (post:Post {id: $postId}), (comment:Comment {id: $commentId})
|
||||
MERGE (post)<-[:COMMENTS]-(comment)
|
||||
RETURN comment {.id, .content}`, {
|
||||
MATCH (post:Post {id: $postId}), (comment:Comment {id: $commentId}), (author:User {id: $userId})
|
||||
MERGE (post)<-[:COMMENTS]-(comment)<-[:WROTE]-(author)
|
||||
RETURN post`, {
|
||||
userId: context.user.id,
|
||||
postId,
|
||||
commentId: comment.id
|
||||
}
|
||||
|
||||
@ -4,7 +4,10 @@ import { host, login } from '../jest/helpers'
|
||||
|
||||
const factory = Factory()
|
||||
let client
|
||||
let variables
|
||||
let createCommentVariables
|
||||
let createPostVariables
|
||||
let createCommentVariablesSansPostId
|
||||
let createCommentVariablesWithNonExistentPost
|
||||
|
||||
beforeEach(async () => {
|
||||
await factory.create('User', {
|
||||
@ -18,7 +21,7 @@ afterEach(async () => {
|
||||
})
|
||||
|
||||
describe('CreateComment', () => {
|
||||
const mutation = `
|
||||
const createCommentMutation = `
|
||||
mutation($postId: ID, $content: String!) {
|
||||
CreateComment(postId: $postId, content: $content) {
|
||||
id
|
||||
@ -26,14 +29,28 @@ describe('CreateComment', () => {
|
||||
}
|
||||
}
|
||||
`
|
||||
const createPostMutation = `
|
||||
mutation($id: ID!, $title: String!, $content: String!) {
|
||||
CreatePost(id: $id, title: $title, content: $content) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
const commentQueryForPostId = `
|
||||
query($content: String) {
|
||||
Comment(content: $content) {
|
||||
postId
|
||||
}
|
||||
}
|
||||
`
|
||||
describe('unauthenticated', () => {
|
||||
it('throws authorization error', async () => {
|
||||
variables = {
|
||||
createCommentVariables = {
|
||||
postId: 'p1',
|
||||
content: 'I\'m not authorised to comment'
|
||||
}
|
||||
client = new GraphQLClient(host)
|
||||
await expect(client.request(mutation, variables)).rejects.toThrow('Not Authorised')
|
||||
await expect(client.request(createCommentMutation, createCommentVariables)).rejects.toThrow('Not Authorised')
|
||||
})
|
||||
})
|
||||
|
||||
@ -42,40 +59,120 @@ describe('CreateComment', () => {
|
||||
beforeEach(async () => {
|
||||
headers = await login({ email: 'test@example.org', password: '1234' })
|
||||
client = new GraphQLClient(host, { headers })
|
||||
})
|
||||
|
||||
it('creates a comment', async () => {
|
||||
variables = {
|
||||
createCommentVariables = {
|
||||
postId: 'p1',
|
||||
content: 'I\'m authorised to comment'
|
||||
}
|
||||
createPostVariables = {
|
||||
id: 'p1',
|
||||
title: 'post to comment on',
|
||||
content: 'please comment on me'
|
||||
}
|
||||
await client.request(createPostMutation, createPostVariables)
|
||||
})
|
||||
|
||||
it('creates a comment', async () => {
|
||||
const expected = {
|
||||
CreateComment: {
|
||||
content: 'I\'m authorised to comment'
|
||||
}
|
||||
}
|
||||
|
||||
await expect(client.request(mutation, variables)).resolves.toMatchObject(expected)
|
||||
await expect(client.request(createCommentMutation, createCommentVariables)).resolves.toMatchObject(expected)
|
||||
})
|
||||
|
||||
it('throw an error if an empty string is sent as content', async () => {
|
||||
variables = {
|
||||
it('assigns the authenticated user as author', async () => {
|
||||
await client.request(createCommentMutation, createCommentVariables)
|
||||
|
||||
const { User } = await client.request(`{
|
||||
User(email: "test@example.org") {
|
||||
comments {
|
||||
content
|
||||
}
|
||||
}
|
||||
}`)
|
||||
|
||||
expect(User).toEqual([ { comments: [ { content: 'I\'m authorised to comment' } ] } ])
|
||||
})
|
||||
|
||||
it('throw an error if an empty string is sent from the editor as content', async () => {
|
||||
createCommentVariables = {
|
||||
postId: 'p1',
|
||||
content: '<p></p>'
|
||||
}
|
||||
|
||||
await expect(client.request(mutation, variables))
|
||||
await expect(client.request(createCommentMutation, createCommentVariables))
|
||||
.rejects.toThrow('Comment must be at least 1 character long!')
|
||||
})
|
||||
|
||||
it('throws an error if a comment does not contain a single character', async () => {
|
||||
variables = {
|
||||
it('throws an error if a comment sent from the editor does not contain a single character', async () => {
|
||||
createCommentVariables = {
|
||||
postId: 'p1',
|
||||
content: '<p> </p>'
|
||||
}
|
||||
|
||||
await expect(client.request(mutation, variables))
|
||||
await expect(client.request(createCommentMutation, createCommentVariables))
|
||||
.rejects.toThrow('Comment must be at least 1 character long!')
|
||||
})
|
||||
|
||||
it('throws an error if postId is sent as an empty string', async () => {
|
||||
createCommentVariables = {
|
||||
postId: 'p1',
|
||||
content: ''
|
||||
}
|
||||
|
||||
await expect(client.request(createCommentMutation, createCommentVariables))
|
||||
.rejects.toThrow('Comment must be at least 1 character long!')
|
||||
})
|
||||
|
||||
it('throws an error if content is sent as an string of empty characters', async () => {
|
||||
createCommentVariables = {
|
||||
postId: 'p1',
|
||||
content: ' '
|
||||
}
|
||||
|
||||
await expect(client.request(createCommentMutation, createCommentVariables))
|
||||
.rejects.toThrow('Comment must be at least 1 character long!')
|
||||
})
|
||||
|
||||
it('throws an error if postId is sent as an empty string', async () => {
|
||||
createCommentVariablesSansPostId = {
|
||||
postId: '',
|
||||
content: 'this comment should not be created'
|
||||
}
|
||||
|
||||
await expect(client.request(createCommentMutation, createCommentVariablesSansPostId))
|
||||
.rejects.toThrow('Comment cannot be created without a post!')
|
||||
})
|
||||
|
||||
it('throws an error if postId is sent as an string of empty characters', async () => {
|
||||
createCommentVariablesSansPostId = {
|
||||
postId: ' ',
|
||||
content: 'this comment should not be created'
|
||||
}
|
||||
|
||||
await expect(client.request(createCommentMutation, createCommentVariablesSansPostId))
|
||||
.rejects.toThrow('Comment cannot be created without a post!')
|
||||
})
|
||||
|
||||
it('throws an error if the post does not exist in the database', async () => {
|
||||
createCommentVariablesWithNonExistentPost = {
|
||||
postId: 'p2',
|
||||
content: 'comment should not be created cause the post doesn\'t exist'
|
||||
}
|
||||
|
||||
await expect(client.request(createCommentMutation, createCommentVariablesWithNonExistentPost))
|
||||
.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 }])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -16,6 +16,9 @@ const setupAuthenticateClient = (params) => {
|
||||
|
||||
let createResource
|
||||
let authenticateClient
|
||||
let createPostVariables
|
||||
let createCommentVariables
|
||||
|
||||
beforeEach(() => {
|
||||
createResource = () => {}
|
||||
authenticateClient = () => {
|
||||
@ -103,18 +106,21 @@ describe('disable', () => {
|
||||
variables = {
|
||||
id: 'c47'
|
||||
}
|
||||
|
||||
createPostVariables = {
|
||||
id: 'p3',
|
||||
title: 'post to comment on',
|
||||
content: 'please comment on me'
|
||||
}
|
||||
createCommentVariables = {
|
||||
id: 'c47',
|
||||
postId: 'p3',
|
||||
content: 'this comment was created for this post'
|
||||
}
|
||||
createResource = async () => {
|
||||
await factory.create('User', { id: 'u45', email: 'commenter@example.org', password: '1234' })
|
||||
await factory.authenticateAs({ email: 'commenter@example.org', password: '1234' })
|
||||
await Promise.all([
|
||||
factory.create('Post', { id: 'p3' }),
|
||||
factory.create('Comment', { id: 'c47', postId: 'p3', content: 'this comment was created for this post' })
|
||||
])
|
||||
|
||||
await Promise.all([
|
||||
factory.relate('Comment', 'Author', { from: 'u45', to: 'c47' })
|
||||
])
|
||||
const asAuthenticatedUser = await factory.authenticateAs({ email: 'commenter@example.org', password: '1234' })
|
||||
await asAuthenticatedUser.create('Post', createPostVariables)
|
||||
await asAuthenticatedUser.create('Comment', createCommentVariables)
|
||||
}
|
||||
})
|
||||
|
||||
@ -277,17 +283,21 @@ describe('enable', () => {
|
||||
variables = {
|
||||
id: 'c456'
|
||||
}
|
||||
|
||||
createPostVariables = {
|
||||
id: 'p9',
|
||||
title: 'post to comment on',
|
||||
content: 'please comment on me'
|
||||
}
|
||||
createCommentVariables = {
|
||||
id: 'c456',
|
||||
postId: 'p9',
|
||||
content: 'this comment was created for this post'
|
||||
}
|
||||
createResource = async () => {
|
||||
await factory.create('User', { id: 'u123', email: 'author@example.org', password: '1234' })
|
||||
await factory.authenticateAs({ email: 'author@example.org', password: '1234' })
|
||||
await Promise.all([
|
||||
factory.create('Post', { id: 'p9' }),
|
||||
factory.create('Comment', { id: 'c456' })
|
||||
])
|
||||
await Promise.all([
|
||||
factory.relate('Comment', 'Author', { from: 'u123', to: 'c456' })
|
||||
])
|
||||
const asAuthenticatedUser = await factory.authenticateAs({ email: 'author@example.org', password: '1234' })
|
||||
await asAuthenticatedUser.create('Post', createPostVariables)
|
||||
await asAuthenticatedUser.create('Comment', createCommentVariables)
|
||||
|
||||
const disableMutation = `
|
||||
mutation {
|
||||
|
||||
@ -9,6 +9,7 @@ describe('report', () => {
|
||||
let headers
|
||||
let returnedObject
|
||||
let variables
|
||||
let createPostVariables
|
||||
|
||||
beforeEach(async () => {
|
||||
returnedObject = '{ description }'
|
||||
@ -128,8 +129,14 @@ describe('report', () => {
|
||||
|
||||
describe('reported resource is a comment', () => {
|
||||
beforeEach(async () => {
|
||||
await factory.authenticateAs({ email: 'test@example.org', password: '1234' })
|
||||
await factory.create('Comment', { id: 'c34', content: 'Robert getting tired.' })
|
||||
createPostVariables = {
|
||||
id: 'p1',
|
||||
title: 'post to comment on',
|
||||
content: 'please comment on me'
|
||||
}
|
||||
const asAuthenticatedUser = await factory.authenticateAs({ email: 'test@example.org', password: '1234' })
|
||||
await asAuthenticatedUser.create('Post', createPostVariables)
|
||||
await asAuthenticatedUser.create('Comment', { postId: 'p1', id: 'c34', content: 'Robert getting tired.' })
|
||||
variables = { id: 'c34' }
|
||||
})
|
||||
|
||||
|
||||
@ -189,33 +189,18 @@ import Factory from './factories'
|
||||
])
|
||||
|
||||
await Promise.all([
|
||||
f.create('Comment', { id: 'c1', postId: 'p1' }),
|
||||
f.create('Comment', { id: 'c2', postId: 'p1' }),
|
||||
f.create('Comment', { id: 'c3', postId: 'p3' }),
|
||||
f.create('Comment', { id: 'c4', postId: 'p2' }),
|
||||
f.create('Comment', { id: 'c5', postId: 'p3' }),
|
||||
f.create('Comment', { id: 'c6', postId: 'p4' }),
|
||||
f.create('Comment', { id: 'c7', postId: 'p2' }),
|
||||
f.create('Comment', { id: 'c8', postId: 'p15' }),
|
||||
f.create('Comment', { id: 'c9', postId: 'p15' }),
|
||||
f.create('Comment', { id: 'c10', postId: 'p15' }),
|
||||
f.create('Comment', { id: 'c11', postId: 'p15' }),
|
||||
f.create('Comment', { id: 'c12', postId: 'p15' })
|
||||
])
|
||||
|
||||
await Promise.all([
|
||||
f.relate('Comment', 'Author', { from: 'u3', to: 'c1' }),
|
||||
f.relate('Comment', 'Author', { from: 'u1', to: 'c2' }),
|
||||
f.relate('Comment', 'Author', { from: 'u1', to: 'c3' }),
|
||||
f.relate('Comment', 'Author', { from: 'u4', to: 'c4' }),
|
||||
f.relate('Comment', 'Author', { from: 'u4', to: 'c5' }),
|
||||
f.relate('Comment', 'Author', { from: 'u3', to: 'c6' }),
|
||||
f.relate('Comment', 'Author', { from: 'u2', to: 'c7' }),
|
||||
f.relate('Comment', 'Author', { from: 'u5', to: 'c8' }),
|
||||
f.relate('Comment', 'Author', { from: 'u6', to: 'c9' }),
|
||||
f.relate('Comment', 'Author', { from: 'u7', to: 'c10' }),
|
||||
f.relate('Comment', 'Author', { from: 'u5', to: 'c11' }),
|
||||
f.relate('Comment', 'Author', { from: 'u6', to: 'c12' })
|
||||
asUser.create('Comment', { id: 'c1', postId: 'p1' }),
|
||||
asTick.create('Comment', { id: 'c2', postId: 'p1' }),
|
||||
asTrack.create('Comment', { id: 'c3', postId: 'p3' }),
|
||||
asTrick.create('Comment', { id: 'c4', postId: 'p2' }),
|
||||
asModerator.create('Comment', { id: 'c5', postId: 'p3' }),
|
||||
asAdmin.create('Comment', { id: 'c6', postId: 'p4' }),
|
||||
asUser.create('Comment', { id: 'c7', postId: 'p2' }),
|
||||
asTick.create('Comment', { id: 'c8', postId: 'p15' }),
|
||||
asTrick.create('Comment', { id: 'c9', postId: 'p15' }),
|
||||
asTrack.create('Comment', { id: 'c10', postId: 'p15' }),
|
||||
asUser.create('Comment', { id: 'c11', postId: 'p15' }),
|
||||
asUser.create('Comment', { id: 'c12', postId: 'p15' })
|
||||
])
|
||||
|
||||
const disableMutation = 'mutation($id: ID!) { disable(id: $id) }'
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
|
||||
const narratorAvatar = 'https://s3.amazonaws.com/uifaces/faces/twitter/nerrsoft/128.jpg'
|
||||
|
||||
Then('I click on the {string} button', text => {
|
||||
cy.get('button').contains(text).click()
|
||||
})
|
||||
@ -12,6 +14,9 @@ Then('my comment should be successfully created', () => {
|
||||
Then('I should see my comment', () => {
|
||||
cy.get('div.comment p')
|
||||
.should('contain', 'Human Connection rocks')
|
||||
.get('.ds-avatar img')
|
||||
.should('have.attr', 'src')
|
||||
.and('contain', narratorAvatar)
|
||||
})
|
||||
|
||||
Then('the editor should be cleared', () => {
|
||||
|
||||
@ -11,6 +11,7 @@ let loginCredentials = {
|
||||
}
|
||||
const narratorParams = {
|
||||
name: 'Peter Pan',
|
||||
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/nerrsoft/128.jpg',
|
||||
...loginCredentials
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
<ds-button
|
||||
:disabled="disabled"
|
||||
ghost
|
||||
class="cancelBtn"
|
||||
@click.prevent="clear"
|
||||
>
|
||||
{{ $t('actions.cancel') }}
|
||||
@ -28,6 +29,7 @@
|
||||
<ds-flex-item :width="{ base: '40%', md: '20%', sm: '40%', xs: '40%' }">
|
||||
<ds-button
|
||||
type="submit"
|
||||
:loading="loading"
|
||||
:disabled="disabled || errors"
|
||||
primary
|
||||
>
|
||||
@ -55,6 +57,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
disabled: true,
|
||||
loading: false,
|
||||
form: {
|
||||
content: ''
|
||||
},
|
||||
@ -75,6 +78,8 @@ export default {
|
||||
this.$refs.editor.clear()
|
||||
},
|
||||
handleSubmit() {
|
||||
this.loading = true
|
||||
this.disabled = true
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: gql`
|
||||
@ -91,9 +96,11 @@ export default {
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
this.$emit('addComment', res.data.CreateComment)
|
||||
this.loading = false
|
||||
this.$root.$emit('refetchPostComments', res.data.CreateComment)
|
||||
this.$refs.editor.clear()
|
||||
this.$toast.success(this.$t('post.comment.submitted'))
|
||||
this.disabled = false
|
||||
})
|
||||
.catch(err => {
|
||||
this.$toast.error(err.message)
|
||||
69
webapp/components/comments/CommentList/CommentList.spec.js
Normal file
69
webapp/components/comments/CommentList/CommentList.spec.js
Normal file
@ -0,0 +1,69 @@
|
||||
import { config, mount, createLocalVue } from '@vue/test-utils'
|
||||
import CommentList from '.'
|
||||
import Empty from '~/components/Empty'
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import Filters from '~/plugins/vue-filters'
|
||||
import Styleguide from '@human-connection/styleguide'
|
||||
|
||||
const localVue = createLocalVue()
|
||||
|
||||
localVue.use(Styleguide)
|
||||
localVue.use(Vuex)
|
||||
localVue.filter('truncate', string => string)
|
||||
|
||||
config.stubs['v-popover'] = '<span><slot /></span>'
|
||||
config.stubs['nuxt-link'] = '<span><slot /></span>'
|
||||
config.stubs['no-ssr'] = '<span><slot /></span>'
|
||||
|
||||
describe('CommentList.vue', () => {
|
||||
let mocks
|
||||
let store
|
||||
let wrapper
|
||||
let propsData
|
||||
let data
|
||||
|
||||
propsData = {
|
||||
post: { id: 1 }
|
||||
}
|
||||
store = new Vuex.Store({
|
||||
getters: {
|
||||
'auth/user': () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
})
|
||||
mocks = {
|
||||
$t: jest.fn()
|
||||
}
|
||||
data = () => {
|
||||
return {
|
||||
comments: []
|
||||
}
|
||||
}
|
||||
|
||||
describe('shallowMount', () => {
|
||||
const Wrapper = () => {
|
||||
return mount(CommentList, { store, mocks, localVue, propsData, data })
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
comments: [{ id: 'c1', contentExcerpt: 'this is a comment' }]
|
||||
})
|
||||
})
|
||||
|
||||
it('displays a message icon when there are no comments to display', () => {
|
||||
expect(Wrapper().findAll(Empty)).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('displays a comments counter', () => {
|
||||
expect(wrapper.find('span.ds-tag').text()).toEqual('1')
|
||||
})
|
||||
|
||||
it('displays comments when there are comments to display', () => {
|
||||
expect(wrapper.find('div#comments').text()).toEqual('this is a comment')
|
||||
})
|
||||
})
|
||||
})
|
||||
80
webapp/components/comments/CommentList/index.vue
Normal file
80
webapp/components/comments/CommentList/index.vue
Normal file
@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div>
|
||||
<h3 style="margin-top: -10px;">
|
||||
<span>
|
||||
<ds-icon name="comments" />
|
||||
<ds-tag
|
||||
v-if="comments"
|
||||
style="margin-top: -4px; margin-left: -12px; position: absolute;"
|
||||
color="primary"
|
||||
size="small"
|
||||
round
|
||||
>{{ comments.length }}</ds-tag> Comments
|
||||
</span>
|
||||
</h3>
|
||||
<ds-space margin-bottom="large" />
|
||||
<div
|
||||
v-if="comments && comments.length"
|
||||
id="comments"
|
||||
class="comments"
|
||||
>
|
||||
<comment
|
||||
v-for="comment in comments"
|
||||
:key="comment.id"
|
||||
:comment="comment"
|
||||
/>
|
||||
</div>
|
||||
<hc-empty
|
||||
v-else
|
||||
name="empty"
|
||||
icon="messages"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Comment from '~/components/Comment.vue'
|
||||
import HcEmpty from '~/components/Empty.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Comment,
|
||||
HcEmpty
|
||||
},
|
||||
props: {
|
||||
post: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
comments: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
Post(post) {
|
||||
this.comments = post[0].comments || []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$root.$on('refetchPostComments', comment => {
|
||||
this.refetchPostComments(comment)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
refetchPostComments(comment) {
|
||||
this.$apollo.queries.Post.refetch()
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
Post: {
|
||||
query() {
|
||||
return require('~/graphql/PostCommentsQuery.js').default(this)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
slug: this.post.slug
|
||||
}
|
||||
},
|
||||
fetchPolicy: 'cache-and-network'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -1,12 +1,34 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export default app => {
|
||||
const lang = app.$i18n.locale().toUpperCase()
|
||||
return gql(`
|
||||
query CommentByPost($postId: ID!) {
|
||||
CommentByPost(postId: $postId) {
|
||||
query Comment($postId: ID) {
|
||||
Comment(postId: $postId) {
|
||||
id
|
||||
contentExcerpt
|
||||
createdAt
|
||||
author {
|
||||
id
|
||||
slug
|
||||
name
|
||||
avatar
|
||||
disabled
|
||||
deleted
|
||||
shoutedCount
|
||||
contributionsCount
|
||||
commentsCount
|
||||
followedByCount
|
||||
followedByCurrentUser
|
||||
location {
|
||||
name: name${lang}
|
||||
}
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
39
webapp/graphql/PostCommentsQuery.js
Normal file
39
webapp/graphql/PostCommentsQuery.js
Normal file
@ -0,0 +1,39 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export default app => {
|
||||
const lang = app.$i18n.locale().toUpperCase()
|
||||
return gql(`
|
||||
query Post($slug: String!) {
|
||||
Post(slug: $slug) {
|
||||
comments(orderBy: createdAt_asc) {
|
||||
id
|
||||
contentExcerpt
|
||||
createdAt
|
||||
disabled
|
||||
deleted
|
||||
author {
|
||||
id
|
||||
slug
|
||||
name
|
||||
avatar
|
||||
disabled
|
||||
deleted
|
||||
shoutedCount
|
||||
contributionsCount
|
||||
commentsCount
|
||||
followedByCount
|
||||
followedByCurrentUser
|
||||
location {
|
||||
name: name${lang}
|
||||
}
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
}
|
||||
@ -96,39 +96,9 @@
|
||||
<ds-space margin="small" />
|
||||
<!-- Comments -->
|
||||
<ds-section slot="footer">
|
||||
<h3 style="margin-top: -10px;">
|
||||
<span>
|
||||
<ds-icon name="comments" />
|
||||
<ds-tag
|
||||
v-if="comments"
|
||||
style="margin-top: -4px; margin-left: -12px; position: absolute;"
|
||||
color="primary"
|
||||
size="small"
|
||||
round
|
||||
>{{ comments.length }}</ds-tag> Comments
|
||||
</span>
|
||||
</h3>
|
||||
<hc-comment-list :post="post" />
|
||||
<ds-space margin-bottom="large" />
|
||||
<div
|
||||
v-if="comments && comments.length"
|
||||
id="comments"
|
||||
class="comments"
|
||||
>
|
||||
<comment
|
||||
v-for="comment in comments"
|
||||
:key="comment.id"
|
||||
:comment="comment"
|
||||
/>
|
||||
</div>
|
||||
<hc-empty
|
||||
v-else
|
||||
icon="messages"
|
||||
/>
|
||||
<ds-space margin-bottom="large" />
|
||||
<hc-comment-form
|
||||
:post="post"
|
||||
@addComment="addComment"
|
||||
/>
|
||||
<hc-comment-form :post="post" />
|
||||
</ds-section>
|
||||
</ds-card>
|
||||
</transition>
|
||||
@ -142,9 +112,8 @@ import HcTag from '~/components/Tag'
|
||||
import ContentMenu from '~/components/ContentMenu'
|
||||
import HcUser from '~/components/User'
|
||||
import HcShoutButton from '~/components/ShoutButton.vue'
|
||||
import HcEmpty from '~/components/Empty.vue'
|
||||
import HcCommentForm from '~/components/CommentForm'
|
||||
import Comment from '~/components/Comment.vue'
|
||||
import HcCommentForm from '~/components/comments/CommentForm'
|
||||
import HcCommentList from '~/components/comments/CommentList'
|
||||
|
||||
export default {
|
||||
transition: {
|
||||
@ -156,10 +125,9 @@ export default {
|
||||
HcCategory,
|
||||
HcUser,
|
||||
HcShoutButton,
|
||||
HcEmpty,
|
||||
Comment,
|
||||
ContentMenu,
|
||||
HcCommentForm
|
||||
HcCommentForm,
|
||||
HcCommentList
|
||||
},
|
||||
head() {
|
||||
return {
|
||||
@ -169,7 +137,6 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
post: null,
|
||||
comments: null,
|
||||
ready: false,
|
||||
title: 'loading'
|
||||
}
|
||||
@ -178,9 +145,6 @@ export default {
|
||||
Post(post) {
|
||||
this.post = post[0] || {}
|
||||
this.title = this.post.title
|
||||
},
|
||||
CommentByPost(comments) {
|
||||
this.comments = comments || []
|
||||
}
|
||||
},
|
||||
async asyncData(context) {
|
||||
@ -289,22 +253,6 @@ export default {
|
||||
methods: {
|
||||
isAuthor(id) {
|
||||
return this.$store.getters['auth/user'].id === id
|
||||
},
|
||||
addComment(comment) {
|
||||
this.$apollo.queries.CommentByPost.refetch()
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
CommentByPost: {
|
||||
query() {
|
||||
return require('~/graphql/CommentQuery.js').default(this)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
postId: this.post.id
|
||||
}
|
||||
},
|
||||
fetchPolicy: 'cache-and-network'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user