Refactoring and second approach to change the database

This commit is contained in:
Wolfgang Huß 2019-06-28 16:47:26 +02:00
parent 1d1959561b
commit 28e4433b87
7 changed files with 87 additions and 96 deletions

View File

@ -1,57 +1,34 @@
import extractMentionedUsers from './notifications/extractMentionedUsers'
import extractHashtags from './hashtags/extractHashtags'
const notify = async (resolve, root, args, context, resolveInfo) => {
// extract user ids before xss-middleware removes link classes
const ids = extractMentionedUsers(args.content)
console.log('ids: ', ids)
const post = await resolve(root, args, context, resolveInfo)
const notify = async (postId, idsOfMentionedUsers, context) => {
const session = context.driver.session()
const {
id: postId
} = post
const createdAt = new Date().toISOString()
const cypher = `
match(u:User) where u.id in $ids
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)
merge (p)-[:NOTIFIED]->(n)
`
await session.run(cypher, {
ids,
idsOfMentionedUsers,
createdAt,
postId
})
session.close()
return post
}
const updateHashtagsOfPost = async (postId, resolve, root, args, context, resolveInfo) => {
// extract tag (hashtag) ids before xss-middleware removes link classes
const hashtags = extractHashtags(args.content)
console.log('hashtags: ', hashtags)
// const post = await resolve(root, args, context, resolveInfo)
const updateHashtagsOfPost = async (postId, hashtags, context) => {
const session = context.driver.session()
// const {
// id: postId
// } = post
// const createdAt = new Date().toISOString()
const cypher = `
MATCH (p:Post { id: $postId })-[oldRelations:TAGGED]->(oldTags:Tag)
DELETE oldRelations
WITH p
UNWIND $hashtags AS tagName
MERGE (t: Tag { id: tagName, name: tagName })
MERGE (t:Tag { id: tagName, name: tagName, disabled: false, deleted: false })
MERGE (p)-[:TAGGED]->(t)
RETURN t
RETURN p, t
`
await session.run(cypher, {
postId,
@ -61,10 +38,20 @@ const updateHashtagsOfPost = async (postId, resolve, root, args, context, resolv
}
const handleContentData = async (resolve, root, args, context, resolveInfo) => {
// extract user ids before xss-middleware removes link classes
console.log('args.content: ', args.content)
// extract user ids before xss-middleware removes classes via the following "resolve" call
const idsOfMentionedUsers = extractMentionedUsers(args.content)
console.log('idsOfMentionedUsers: ', idsOfMentionedUsers)
// extract tag (hashtag) ids before xss-middleware removes classes via the following "resolve" call
const hashtags = extractHashtags(args.content)
console.log('hashtags: ', hashtags)
const post = await notify(resolve, root, args, context, resolveInfo)
await updateHashtagsOfPost(post.id, resolve, root, args, context, resolveInfo)
// removes classes from the content
const post = await resolve(root, args, context, resolveInfo)
console.log('post.id: ', post.id)
await notify(post.id, idsOfMentionedUsers, context)
await updateHashtagsOfPost(post.id, hashtags, context)
return post
}

View File

@ -11,6 +11,7 @@ export default function(content) {
.get()
const ids = []
urls.forEach(url => {
console.log('url: ', url)
let match
while ((match = ID_REGEX.exec(url)) != null) {
ids.push(match[1])

View File

@ -39,7 +39,9 @@ describe('ContributionForm.vue', () => {
},
},
})
.mockRejectedValue({ message: 'Not Authorised!' }),
.mockRejectedValue({
message: 'Not Authorised!',
}),
},
$toast: {
error: jest.fn(),
@ -66,12 +68,26 @@ describe('ContributionForm.vue', () => {
getters,
})
const Wrapper = () => {
return mount(ContributionForm, { mocks, localVue, store, propsData })
return mount(ContributionForm, {
mocks,
localVue,
store,
propsData,
})
}
beforeEach(() => {
wrapper = Wrapper()
wrapper.setData({ form: { languageOptions: [{ label: 'Deutsch', value: 'de' }] } })
wrapper.setData({
form: {
languageOptions: [
{
label: 'Deutsch',
value: 'de',
},
],
},
})
})
describe('CreatePost', () => {
@ -100,7 +116,12 @@ describe('ContributionForm.vue', () => {
beforeEach(async () => {
expectedParams = {
mutation: PostMutations().CreatePost,
variables: { title: postTitle, content: postContent, language: 'en', id: null },
variables: {
title: postTitle,
content: postContent,
language: 'en',
id: null,
},
}
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
@ -124,25 +145,13 @@ describe('ContributionForm.vue', () => {
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
it('supports adding tags', async () => {
it.skip('supports adding tags', async () => {
expectedParams.variables.tags = ['Frieden']
tagsInput = wrapper.findAll('input').at(1)
tagsInput.setValue('Frieden')
tagsInput.trigger('keyup.enter')
await wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
it('displays tags if they exist', () => {
it.skip('displays tags if they exist', () => {
expectedParams.variables.tags = ['Frieden']
tagsInput = wrapper.findAll('input').at(1)
tagsInput.setValue('Frieden')
tagsInput.trigger('keyup.enter')
chipText = wrapper
.findAll('span.ds-chip')
.at(0)
.text()
expect(chipText).toEqual('Frieden')
})
it("pushes the user to the post's page", async () => {
@ -210,7 +219,9 @@ describe('ContributionForm.vue', () => {
})
it('sets language equal to contribution language', () => {
expect(wrapper.vm.form.language).toEqual({ value: propsData.contribution.language })
expect(wrapper.vm.form.language).toEqual({
value: propsData.contribution.language,
})
})
it('calls the UpdatePost apollo mutation', async () => {

View File

@ -12,17 +12,6 @@
/>
</no-ssr>
<ds-space margin-bottom="xxx-large" />
<ds-input
model="tagValue"
:label="$t('contribution.tagsInputLabel')"
:placeholder="$t('contribution.tagsInputPlaceholder')"
@input.native="handleInput"
@keyup.enter.native="addTag(form.tagValue)"
:disabled="form.tags.length >= 5"
></ds-input>
<ds-chip v-for="(tag, index) in form.tags" @remove="removeTag(index)" removable :key="tag">
{{ tag }}
</ds-chip>
<ds-flex class="contribution-form-footer">
<ds-flex-item :width="{ base: '10%', sm: '10%', md: '10%', lg: '15%' }" />
<ds-flex-item :width="{ base: '80%', sm: '30%', md: '30%', lg: '20%' }">
@ -82,8 +71,6 @@ export default {
content: '',
language: null,
languageOptions: [],
tagValue: null,
tags: [],
},
formSchema: {
title: { required: true, min: 3, max: 64 },
@ -135,7 +122,6 @@ export default {
title: this.form.title,
content: this.form.content,
language: this.form.language ? this.form.language.value : this.$i18n.locale(),
tags: this.form.tags,
},
})
.then(res => {
@ -165,16 +151,6 @@ export default {
this.form.languageOptions.push({ label: locale.name, value: locale.code })
})
},
removeTag(index) {
this.form.tags.splice(index, 1)
},
handleInput(e) {
this.form.tagValue = e.target ? e.target.value.trim() : ''
},
addTag(tag) {
this.form.tags.push(tag)
this.form.tagValue = ''
},
},
apollo: {
User: {

View File

@ -12,10 +12,19 @@
<div v-if="isMention">@{{ item.slug }}</div>
<div v-if="isHashtag">#{{ item.name }}</div>
</div>
<div
v-if="isHashtag && query && !filteredItems.find(el => el.name === query)"
class="suggestion-list__item is-empty"
>
{{ $t('editor.hashtag.addHashtag') }}
</div>
</template>
<div v-else class="suggestion-list__item is-empty">
<div v-if="isMention">{{ $t('editor.mention.noUsersFound') }}</div>
<div v-if="isHashtag">{{ $t('editor.hashtag.noHashtagsFound') }}</div>
<div v-if="isHashtag">
<div v-if="query === ''">{{ $t('editor.hashtag.noHashtagsFound') }}</div>
<div v-else>{{ $t('editor.hashtag.addHashtag') }}</div>
</div>
</div>
</div>
@ -271,7 +280,7 @@ export default {
}
// pressing enter
if (event.keyCode === 13) {
this.enterHandler(this.mentionSuggestionType)
this.enterHandler()
return true
}
return false
@ -340,9 +349,14 @@ export default {
this.downHandler()
return true
}
// pressing enter or pressing space
if (event.keyCode === 13 || event.keyCode === 32) {
this.enterHandler(this.hashtagSuggestionType)
// pressing enter
if (event.keyCode === 13) {
this.enterHandler()
return true
}
// pressing space
if (event.keyCode === 32) {
this.spaceHandler()
return true
}
return false
@ -357,7 +371,7 @@ export default {
}
const fuse = new Fuse(items, {
threshold: 0.2,
keys: ['slug'],
keys: ['name'],
})
return fuse.search(query)
},
@ -434,13 +448,17 @@ export default {
downHandler() {
this.navigatedItemIndex = (this.navigatedItemIndex + 1) % this.filteredItems.length
},
// For hashtags handles pressing of space as enter.
// Handles pressing of enter.
enterHandler() {
const item = this.filteredItems[this.navigatedItemIndex]
if (item) {
this.selectItem(item)
} else if (this.suggestionType === this.hashtagSuggestionType && this.query !== '') {
this.selectItem({ name: this.query }, this.hashtagSuggestionType)
}
},
// For hashtags handles pressing of space.
spaceHandler() {
if (this.suggestionType === this.hashtagSuggestionType && this.query !== '') {
this.selectItem({ name: this.query })
}
},
// we have to replace our suggestion text with a mention

View File

@ -40,7 +40,8 @@
"noUsersFound": "Keine Benutzer gefunden"
},
"hashtag": {
"noHashtagsFound": "Keine Hashtags gefunden"
"noHashtagsFound": "Keine Hashtags gefunden",
"addHashtag": "Neuer Hashtag"
}
},
"profile": {
@ -338,9 +339,7 @@
"filterFollow": "Beiträge filtern von Usern denen ich folge",
"filterALL": "Alle Beiträge anzeigen",
"success": "Gespeichert!",
"languageSelectLabel": "Sprache",
"tagsInputLabel": "Tags",
"tagsInputPlaceholder": "Hinzufügen ein Tag"
"languageSelectLabel": "Sprache"
}
}

View File

@ -40,7 +40,8 @@
"noUsersFound": "No users found"
},
"hashtag": {
"noHashtagsFound": "No hashtags found"
"noHashtagsFound": "No hashtags found",
"addHashtag": "New hashtag"
}
},
"profile": {
@ -337,8 +338,6 @@
"filterFollow": "Filter contributions from users I follow",
"filterALL": "View all contributions",
"success": "Saved!",
"languageSelectLabel": "Language",
"tagsInputLabel": "Tags",
"tagsInputPlaceholder": "Add a tag"
"languageSelectLabel": "Language"
}
}