Preparing for Mentions of users in Comments

Co-Authored-By: mattwr18 <mattwr18@gmail.com>
This commit is contained in:
Wolfgang Huß 2019-07-15 17:56:35 +02:00
parent 688da7f705
commit ff234eeed5
7 changed files with 198 additions and 62 deletions

View File

@ -7,7 +7,7 @@ const notifyMentionOfPost = async (postId, idsOfMentionedUsers, context) => {
const session = context.driver.session()
const createdAt = new Date().toISOString()
const cypher = `
MATCH (u: User) WHERE u.id in $idsOfMentionedUsers
MATCH (u: User) WHERE u.id IN $idsOfMentionedUsers
MATCH (p: Post) WHERE p.id = $postId
CREATE (n: Notification { id: apoc.create.uuid(), read: false, createdAt: $createdAt })
MERGE (n)-[:NOTIFIED]->(u)

View File

@ -1,6 +1,11 @@
import { GraphQLClient } from 'graphql-request'
import {
GraphQLClient
} from 'graphql-request'
import Factory from '../../seed/factories'
import { host, login } from '../../jest/helpers'
import {
host,
login
} from '../../jest/helpers'
const factory = Factory()
let client
@ -39,8 +44,13 @@ describe('currentUser { notifications }', () => {
describe('authenticated', () => {
let headers
beforeEach(async () => {
headers = await login({ email: 'test@example.org', password: '1234' })
client = new GraphQLClient(host, { headers })
headers = await login({
email: 'test@example.org',
password: '1234'
})
client = new GraphQLClient(host, {
headers
})
})
describe('given some notifications', () => {
@ -52,19 +62,46 @@ describe('currentUser { notifications }', () => {
}
await Promise.all([
factory.create('User', neighborParams),
factory.create('Notification', { id: 'not-for-you' }),
factory.create('Notification', { id: 'already-seen', read: true }),
factory.create('Notification', {
id: 'not-for-you'
}),
factory.create('Notification', {
id: 'already-seen',
read: true
}),
])
await factory.create('Notification', { id: 'unseen' })
await factory.create('Notification', {
id: 'unseen'
})
await factory.authenticateAs(neighborParams)
await factory.create('Post', { id: 'p1' })
await factory.create('Post', {
id: 'p1'
})
await Promise.all([
factory.relate('Notification', 'User', { from: 'not-for-you', to: 'neighbor' }),
factory.relate('Notification', 'Post', { from: 'p1', to: 'not-for-you' }),
factory.relate('Notification', 'User', { from: 'unseen', to: 'you' }),
factory.relate('Notification', 'Post', { from: 'p1', to: 'unseen' }),
factory.relate('Notification', 'User', { from: 'already-seen', to: 'you' }),
factory.relate('Notification', 'Post', { from: 'p1', to: 'already-seen' }),
factory.relate('Notification', 'User', {
from: 'not-for-you',
to: 'neighbor'
}),
factory.relate('Notification', 'Post', {
from: 'p1',
to: 'not-for-you'
}),
factory.relate('Notification', 'User', {
from: 'unseen',
to: 'you'
}),
factory.relate('Notification', 'Post', {
from: 'p1',
to: 'unseen'
}),
factory.relate('Notification', 'User', {
from: 'already-seen',
to: 'you'
}),
factory.relate('Notification', 'Post', {
from: 'p1',
to: 'already-seen'
}),
])
})
@ -79,11 +116,18 @@ describe('currentUser { notifications }', () => {
}
}
}`
let variables = { read: false }
let variables = {
read: false
}
it('returns only unread notifications of current user', async () => {
const expected = {
currentUser: {
notifications: [{ id: 'unseen', post: { id: 'p1' } }],
notifications: [{
id: 'unseen',
post: {
id: 'p1'
}
}],
},
}
await expect(client.request(query, variables)).resolves.toEqual(expected)
@ -104,9 +148,18 @@ describe('currentUser { notifications }', () => {
it('returns all notifications of current user', async () => {
const expected = {
currentUser: {
notifications: [
{ id: 'unseen', post: { id: 'p1' } },
{ id: 'already-seen', post: { id: 'p1' } },
notifications: [{
id: 'unseen',
post: {
id: 'p1'
}
},
{
id: 'already-seen',
post: {
id: 'p1'
}
},
],
},
}
@ -123,7 +176,10 @@ describe('UpdateNotification', () => {
id read
}
}`
const variables = { id: 'to-be-updated', read: true }
const variables = {
id: 'to-be-updated',
read: true
}
describe('given a notifications', () => {
let headers
@ -136,12 +192,22 @@ describe('UpdateNotification', () => {
slug: 'mentioned',
}
await factory.create('User', mentionedParams)
await factory.create('Notification', { id: 'to-be-updated' })
await factory.create('Notification', {
id: 'to-be-updated'
})
await factory.authenticateAs(userParams)
await factory.create('Post', { id: 'p1' })
await factory.create('Post', {
id: 'p1'
})
await Promise.all([
factory.relate('Notification', 'User', { from: 'to-be-updated', to: 'mentioned-1' }),
factory.relate('Notification', 'Post', { from: 'p1', to: 'to-be-updated' }),
factory.relate('Notification', 'User', {
from: 'to-be-updated',
to: 'mentioned-1'
}),
factory.relate('Notification', 'Post', {
from: 'p1',
to: 'to-be-updated'
}),
])
})
@ -154,8 +220,13 @@ describe('UpdateNotification', () => {
describe('authenticated', () => {
beforeEach(async () => {
headers = await login({ email: 'test@example.org', password: '1234' })
client = new GraphQLClient(host, { headers })
headers = await login({
email: 'test@example.org',
password: '1234'
})
client = new GraphQLClient(host, {
headers
})
})
it('throws authorization error', async () => {
@ -164,15 +235,25 @@ describe('UpdateNotification', () => {
describe('and owner', () => {
beforeEach(async () => {
headers = await login({ email: 'mentioned@example.org', password: '1234' })
client = new GraphQLClient(host, { headers })
headers = await login({
email: 'mentioned@example.org',
password: '1234'
})
client = new GraphQLClient(host, {
headers
})
})
it('updates notification', async () => {
const expected = { UpdateNotification: { id: 'to-be-updated', read: true } }
const expected = {
UpdateNotification: {
id: 'to-be-updated',
read: true
}
}
await expect(client.request(mutation, variables)).resolves.toEqual(expected)
})
})
})
})
})
})

View File

@ -55,7 +55,7 @@ type Notification {
read: Boolean
user: User @relation(name: "NOTIFIED", direction: "OUT")
post: Post @relation(name: "NOTIFIED", direction: "IN")
comment: Post @relation(name: "NOTIFIED", direction: "IN")
comment: Comment @relation(name: "NOTIFIED", direction: "IN")
createdAt: String
}

View File

@ -45,42 +45,49 @@ import Factory from './factories'
f.create('User', {
id: 'u1',
name: 'Peter Lustig',
slug: 'peter-lustig',
role: 'admin',
email: 'admin@example.org',
}),
f.create('User', {
id: 'u2',
name: 'Bob der Baumeister',
slug: 'bob-der-baumeister',
role: 'moderator',
email: 'moderator@example.org',
}),
f.create('User', {
id: 'u3',
name: 'Jenny Rostock',
slug: 'jenny-rostock',
role: 'user',
email: 'user@example.org',
}),
f.create('User', {
id: 'u4',
name: 'Tick',
name: 'Huey (Tick)',
slug: 'huey-tick',
role: 'user',
email: 'tick@example.org',
email: 'huey@example.org',
}),
f.create('User', {
id: 'u5',
name: 'Trick',
name: 'Dewey (Trick)',
slug: 'dewey-trick',
role: 'user',
email: 'trick@example.org',
email: 'dewey@example.org',
}),
f.create('User', {
id: 'u6',
name: 'Track',
name: 'Louie (Track)',
slug: 'louie-track',
role: 'user',
email: 'track@example.org',
email: 'louie@example.org',
}),
f.create('User', {
id: 'u7',
name: 'Dagobert',
slug: 'dagobert',
role: 'user',
email: 'dagobert@example.org',
}),
@ -100,15 +107,15 @@ import Factory from './factories'
password: '1234',
}),
Factory().authenticateAs({
email: 'tick@example.org',
email: 'huey@example.org',
password: '1234',
}),
Factory().authenticateAs({
email: 'trick@example.org',
email: 'dewey@example.org',
password: '1234',
}),
Factory().authenticateAs({
email: 'track@example.org',
email: 'louie@example.org',
password: '1234',
}),
])

View File

@ -2,11 +2,9 @@
<ds-space :class="{ notification: true, read: notification.read }" margin-bottom="x-small">
<no-ssr>
<ds-space margin-bottom="x-small">
<hc-user :user="post.author" :date-time="post.createdAt" :trunc="35" />
<hc-user :user="post.author || comment.author" :date-time="post.createdAt" :trunc="35" />
</ds-space>
<ds-text color="soft">
{{ $t('notifications.menu.mentioned') }}
</ds-text>
<ds-text color="soft">{{ $t('notifications.menu.mentioned') }}</ds-text>
</no-ssr>
<ds-space margin-bottom="x-small" />
<nuxt-link
@ -47,6 +45,9 @@ export default {
post() {
return this.notification.post || {}
},
comment() {
return this.notification.comment || {}
},
},
}
</script>

View File

@ -21,26 +21,73 @@ import NotificationList from '../NotificationList'
import Dropdown from '~/components/Dropdown'
import gql from 'graphql-tag'
const MARK_AS_READ = gql(`
mutation($id: ID!, $read: Boolean!) {
UpdateNotification(id: $id, read: $read) {
id
read
const MARK_AS_READ = gql`
mutation($id: ID!, $read: Boolean!) {
UpdateNotification(id: $id, read: $read) {
id
read
}
}
}`)
`
const NOTIFICATIONS = gql(`{
currentUser {
id
notifications(read: false, orderBy: createdAt_desc) {
id read createdAt
post {
id createdAt disabled deleted title contentExcerpt slug
author { id slug name disabled deleted }
const NOTIFICATIONS = gql`
{
currentUser {
id
notifications(read: false, orderBy: createdAt_desc) {
id
read
createdAt
post {
id
createdAt
disabled
deleted
title
contentExcerpt
slug
author {
id
slug
name
disabled
deleted
}
}
comment {
id
createdAt
disabled
deleted
contentExcerpt
author {
id
slug
name
disabled
deleted
}
post {
id
createdAt
disabled
deleted
title
contentExcerpt
slug
author {
id
slug
name
disabled
deleted
}
}
}
}
}
}
}`)
`
export default {
name: 'NotificationMenu',

View File

@ -2,7 +2,7 @@ import gql from 'graphql-tag'
export default i18n => {
const lang = i18n.locale().toUpperCase()
return gql(`
return gql`
query User($id: ID!) {
User(id: $id) {
id
@ -72,5 +72,5 @@ export default i18n => {
}
}
}
`)
`
}