From f7aeb3c61673a706fcc1b82af96630b0c6403d1e Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 25 Nov 2019 11:23:57 +0100 Subject: [PATCH 001/142] added checkbox for blure Images in contribution form --- .../ContributionForm/ContributionForm.spec.js | 8 ++ .../ContributionForm/ContributionForm.vue | 69 ++++++++++++++++++ .../checkbox-set-blank-checked-line.png | Bin 0 -> 1742 bytes 3 files changed, 77 insertions(+) create mode 100644 webapp/static/img/checkbox/checkbox-set-blank-checked-line.png diff --git a/webapp/components/ContributionForm/ContributionForm.spec.js b/webapp/components/ContributionForm/ContributionForm.spec.js index 52f77b3f2..185e9ad56 100644 --- a/webapp/components/ContributionForm/ContributionForm.spec.js +++ b/webapp/components/ContributionForm/ContributionForm.spec.js @@ -245,6 +245,14 @@ describe('ContributionForm.vue', () => { expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1) }) + describe('questionable images should be blurred', () => { + + it('questionable images unset be blurred', async () => { + await wrapper.find('input[type="checkbox"]').trigger('click') + expect(wrapper.find('input[type="checkbox"]').exists()).toBe(true) + }) + }) + it("pushes the user to the post's page", async () => { wrapper.find('form').trigger('submit') await mocks.$apollo.mutate diff --git a/webapp/components/ContributionForm/ContributionForm.vue b/webapp/components/ContributionForm/ContributionForm.vue index 734e3be81..aa74b498c 100644 --- a/webapp/components/ContributionForm/ContributionForm.vue +++ b/webapp/components/ContributionForm/ContributionForm.vue @@ -79,6 +79,28 @@ + + + + +
+ + + Bilder werden Verschwommen dargestellt + + + +
+
+
diff --git a/webapp/static/img/checkbox/checkbox-set-blank-checked-line.png b/webapp/static/img/checkbox/checkbox-set-blank-checked-line.png new file mode 100644 index 0000000000000000000000000000000000000000..5411a44368d8dd45fc4fc6efb4883ac0a058f96a GIT binary patch literal 1742 zcmeHG`)kc%7=LDEtc>4?c0`HNEPGp0b{fVk9GaCa*Ra?9(jm98<<{Dw!-Ss3Bz`cL z9l6%TC_lJ7R@iYlcA+rRvBb{YAD{R87x>8!^49tGea`bdpXc-WJny$+dLXw~a{pu^ z>XkPsC!Z)`CEm~WNW^nWc55G^M4CROU;;uSLu84VNQl%$#*ndOn2eB7m$ZhgCCg-m zth!n@#Fm(eg;-sy7!pguBtoJH(&qi!rBYmH@N z#aMMLkYsC^4U1uQq);o?2pbV23XW(sYK^i{F^Z{R4KR=fOVC0NgMkfbV4+!^AQ$7X zwPLM0eHe>~*|JzxCl@S`6t*H(6zV|=wN}}xScN?J0h;KB9ncRFPzcrl18J~CDR^Ko zumKG$bBX^L^tdJCkTc@ zum%`NqZ72i1A~DLXmu-c)kq`8QEUuGLLbH=5>>ZAZ~cyiw^6rGZ%K}n=et|4XQkul zx#PC&33ik{4Q}}!EvLYn1ZZ3bYzgK;lQ+t{iGTf3ym?D1J`P%!AD96e|K#~oQwQAP zWvK1BW>V2wqLf?imvCTs$^fEnOY(BY7Hm8mi;fLE&!+4L%|p9BZrw7lt^9pc#j(uF zgpw1#Mtp0n+}M3*>ELR98K2l550`DzyT{`hE%WZ*`@Xx_-|xu5j?!WC3YVuRWp;Eu z|Lk8_pSq{@weQ^Hn$<~1n>y19{be7QuB)%jdQnv3@AouPG!AX6e}(nx%JGZCSR~F zem*VI-Znh-Qu*N@E2f1y->fRCjqkm%p(^)7s5)L9-O=bD@}#+|rL;0SzEP)U#JYZ> z?Rq?;<1$_r^geenwz^^Nm4=_ARxBR%=yc1o`#0Y{m~|uMYp=>p3Y7(Xy{DxenVj;h zvH8%c-9A{u_Uxgg*cP literal 0 HcmV?d00001 From 7f3f81822ee563f981034e5d85518d1157320655 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 28 Nov 2019 20:40:35 +0100 Subject: [PATCH 002/142] blur the image ok. --- backend/src/models/Post.js | 1 + backend/src/schema/resolvers/posts.js | 10 +- backend/src/schema/types/type/Post.gql | 6 +- backend/src/seed/seed-db.js | 32 ++++- .../ContributionForm/ContributionForm.spec.js | 5 +- .../ContributionForm/ContributionForm.vue | 111 +++++++++++------- webapp/components/PostCard/PostCard.vue | 40 ++++++- webapp/components/TeaserImage/TeaserImage.vue | 2 + webapp/graphql/Fragments.js | 1 + webapp/graphql/PostMutations.js | 6 + webapp/locales/de.json | 6 +- webapp/locales/en.json | 4 +- 12 files changed, 168 insertions(+), 56 deletions(-) diff --git a/backend/src/models/Post.js b/backend/src/models/Post.js index 5ac8378c2..2d2a164db 100644 --- a/backend/src/models/Post.js +++ b/backend/src/models/Post.js @@ -45,4 +45,5 @@ module.exports = { default: () => new Date().toISOString(), }, language: { type: 'string', allow: [null] }, + checkedBlur: { type: 'boolean', default: false }, } diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index ee6a82d42..44558be4d 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -297,7 +297,15 @@ export default { }, Post: { ...Resolver('Post', { - undefinedToNull: ['activityId', 'objectId', 'image', 'language', 'pinnedAt', 'pinned'], + undefinedToNull: [ + 'activityId', + 'objectId', + 'image', + 'language', + 'pinnedAt', + 'pinned', + 'checkedBlur', + ], hasMany: { tags: '-[:TAGGED]->(related:Tag)', categories: '-[:CATEGORIZED]->(related:Category)', diff --git a/backend/src/schema/types/type/Post.gql b/backend/src/schema/types/type/Post.gql index b29ac5386..f24018567 100644 --- a/backend/src/schema/types/type/Post.gql +++ b/backend/src/schema/types/type/Post.gql @@ -82,6 +82,7 @@ input _PostFilter { emotions_none: _PostEMOTEDFilter emotions_single: _PostEMOTEDFilter emotions_every: _PostEMOTEDFilter + checkedBlur: Boolean } enum _PostOrdering { @@ -127,6 +128,7 @@ type Post { createdAt: String updatedAt: String language: String + checkedBlur: Boolean pinnedAt: String @cypher( statement: "MATCH (this)<-[pinned:PINNED]-(:User) WHERE NOT this.deleted = true AND NOT this.disabled = true RETURN pinned.createdAt" ) @@ -140,7 +142,6 @@ type Post { LIMIT 10 """ ) - tags: [Tag]! @relation(name: "TAGGED", direction: "OUT") categories: [Category]! @relation(name: "CATEGORIZED", direction: "OUT") @@ -183,6 +184,7 @@ type Mutation { language: String categoryIds: [ID] contentExcerpt: String + checkedBlur: Boolean ): Post UpdatePost( id: ID! @@ -195,6 +197,7 @@ type Mutation { visibility: Visibility language: String categoryIds: [ID] + checkedBlur: Boolean ): Post DeletePost(id: ID!): Post AddPostEmotions(to: _PostInput!, data: _EMOTEDInput!): EMOTED @@ -215,6 +218,7 @@ type Query { createdAt: String updatedAt: String language: String + checkedBlur: Boolean first: Int offset: Int orderBy: [_PostOrdering] diff --git a/backend/src/seed/seed-db.js b/backend/src/seed/seed-db.js index 692d95542..1fd819a87 100644 --- a/backend/src/seed/seed-db.js +++ b/backend/src/seed/seed-db.js @@ -352,6 +352,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] language: sample(languages), image: faker.image.unsplash.food(), categoryIds: ['cat16'], + checkedBlur: true, }), factory.create('Post', { author: bobDerBaumeister, @@ -359,24 +360,28 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] language: sample(languages), image: faker.image.unsplash.technology(), categoryIds: ['cat1'], + checkedBlur: false, }), factory.create('Post', { author: huey, id: 'p3', language: sample(languages), categoryIds: ['cat3'], + checkedBlur: false, }), factory.create('Post', { author: dewey, id: 'p4', language: sample(languages), categoryIds: ['cat4'], + checkedBlur: false, }), factory.create('Post', { author: louie, id: 'p5', language: sample(languages), categoryIds: ['cat5'], + checkedBlur: false, }), factory.create('Post', { authorId: 'u1', @@ -384,17 +389,20 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] language: sample(languages), image: faker.image.unsplash.buildings(), categoryIds: ['cat6'], + checkedBlur: false, }), factory.create('Post', { author: huey, id: 'p9', language: sample(languages), categoryIds: ['cat9'], + checkedBlur: false, }), factory.create('Post', { author: dewey, id: 'p10', categoryIds: ['cat10'], + checkedBlur: true, }), factory.create('Post', { author: louie, @@ -402,12 +410,14 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] language: sample(languages), image: faker.image.unsplash.people(), categoryIds: ['cat11'], + checkedBlur: false, }), factory.create('Post', { author: bobDerBaumeister, id: 'p13', language: sample(languages), categoryIds: ['cat13'], + checkedBlur: false, }), factory.create('Post', { author: jennyRostock, @@ -415,12 +425,14 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] language: sample(languages), image: faker.image.unsplash.objects(), categoryIds: ['cat14'], + checkedBlur: false, }), factory.create('Post', { author: huey, id: 'p15', language: sample(languages), categoryIds: ['cat15'], + checkedBlur: false, }), ]) @@ -434,8 +446,20 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] const hashtagAndMention1 = 'The new physics of #QuantenFlussTheorie can explain #QuantumGravity! @peter-lustig got that already. ;-)' const createPostMutation = gql` - mutation($id: ID, $title: String!, $content: String!, $categoryIds: [ID]) { - CreatePost(id: $id, title: $title, content: $content, categoryIds: $categoryIds) { + mutation( + $id: ID + $title: String! + $content: String! + $categoryIds: [ID] + $checkedBlur: Boolean + ) { + CreatePost( + id: $id + title: $title + content: $content + categoryIds: $categoryIds + checkedBlur: $checkedBlur + ) { id } } @@ -449,6 +473,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] title: `Nature Philosophy Yoga`, content: hashtag1, categoryIds: ['cat2'], + checkedBlur: false, }, }), mutate({ @@ -458,6 +483,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] title: 'This is post #7', content: `${mention1} ${faker.lorem.paragraph()}`, categoryIds: ['cat7'], + checkedBlur: false, }, }), mutate({ @@ -468,6 +494,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] title: `Quantum Flow Theory explains Quantum Gravity`, content: hashtagAndMention1, categoryIds: ['cat8'], + checkedBlur: false, }, }), mutate({ @@ -477,6 +504,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] title: 'This is post #12', content: `${mention2} ${faker.lorem.paragraph()}`, categoryIds: ['cat12'], + checkedBlur: false, }, }), ]) diff --git a/webapp/components/ContributionForm/ContributionForm.spec.js b/webapp/components/ContributionForm/ContributionForm.spec.js index 185e9ad56..603724eca 100644 --- a/webapp/components/ContributionForm/ContributionForm.spec.js +++ b/webapp/components/ContributionForm/ContributionForm.spec.js @@ -245,10 +245,9 @@ describe('ContributionForm.vue', () => { expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1) }) - describe('questionable images should be blurred', () => { - + describe('questionable images should be blurred', () => { it('questionable images unset be blurred', async () => { - await wrapper.find('input[type="checkbox"]').trigger('click') + await wrapper.find('input[type="checkbox"]').trigger('click') expect(wrapper.find('input[type="checkbox"]').exists()).toBe(true) }) }) diff --git a/webapp/components/ContributionForm/ContributionForm.vue b/webapp/components/ContributionForm/ContributionForm.vue index aa74b498c..98e515766 100644 --- a/webapp/components/ContributionForm/ContributionForm.vue +++ b/webapp/components/ContributionForm/ContributionForm.vue @@ -15,6 +15,27 @@ /> + + + + + + + + @@ -78,28 +99,7 @@ - - - - - - - +
this.contribution.language === o.value) : null form.categoryIds = this.categoryIds(this.contribution.categories) + form.checkedBlur = this.contribution.checkedBlur + + // console.log(this.contribution.checkedBlur) + // console.log(this.contribution) } + return { form, formSchema: { @@ -186,6 +193,7 @@ export default { }, }, language: { required: true }, + checkedBlur: { required: false }, }, languageOptions, id, @@ -194,9 +202,13 @@ export default { users: [], contentMin: 3, hashtags: [], - checkedBlur: false, elem: null, - elem1: null, + checkedBlur: false, + } + }, + created() { + if (this.contribution && this.contribution.checkedBlur) { + this.checkedChange() } }, computed: { @@ -209,21 +221,29 @@ export default { }, methods: { checkedChange() { - this.elem = this.$el.querySelector('img') - this.elem1 = this.$el.querySelector('img.thumbnail-preview') + // console.log( 'checkedChange') + // console.log( 'this.checkedBlur old', this.checkedBlur) + // console.log( 'THIS', this.$el) + // console.log( 'THIS.form', this.form) + + if (this.$el) { + this.elem = this.$el.querySelector('img') + } else { + } if (this.checkedBlur) { this.elem.classList.remove('img-blur-in') this.checkedBlur = false + this.form.checkedBlur = false + this.form.checkbox = false } else { if (this.elem != null) { - this.elem.classList.add('img-blur-in') + this.elem.classList.add('img-blur-in') } - if (this.elem1 != null) { - this.elem1.classList.add('img-blur-in') - } - this.checkedBlur = true + this.form.checkedBlur = true + this.form.checkbox = true } + // console.log( 'this.checkedBlur new', this.checkedBlur) }, submit() { const { @@ -246,6 +266,7 @@ export default { language, image, imageUpload: teaserImage, + checkedBlur: this.form.checkbox, }, }) .then(({ data }) => { @@ -307,6 +328,21 @@ export default { } + + diff --git a/webapp/components/PostCard/PostCard.vue b/webapp/components/PostCard/PostCard.vue index e65e17102..78f9f9e95 100644 --- a/webapp/components/PostCard/PostCard.vue +++ b/webapp/components/PostCard/PostCard.vue @@ -2,8 +2,17 @@ + + + + + + diff --git a/webapp/pages/moderation/images.vue b/webapp/pages/moderation/images.vue deleted file mode 100644 index 86e222f0e..000000000 --- a/webapp/pages/moderation/images.vue +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index 769b978b8..7331daf6d 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -12,21 +12,21 @@ > 4?c0`HNEPGp0b{fVk9GaCa*Ra?9(jm98<<{Dw!-Ss3Bz`cL z9l6%TC_lJ7R@iYlcA+rRvBb{YAD{R87x>8!^49tGea`bdpXc-WJny$+dLXw~a{pu^ z>XkPsC!Z)`CEm~WNW^nWc55G^M4CROU;;uSLu84VNQl%$#*ndOn2eB7m$ZhgCCg-m zth!n@#Fm(eg;-sy7!pguBtoJH(&qi!rBYmH@N z#aMMLkYsC^4U1uQq);o?2pbV23XW(sYK^i{F^Z{R4KR=fOVC0NgMkfbV4+!^AQ$7X zwPLM0eHe>~*|JzxCl@S`6t*H(6zV|=wN}}xScN?J0h;KB9ncRFPzcrl18J~CDR^Ko zumKG$bBX^L^tdJCkTc@ zum%`NqZ72i1A~DLXmu-c)kq`8QEUuGLLbH=5>>ZAZ~cyiw^6rGZ%K}n=et|4XQkul zx#PC&33ik{4Q}}!EvLYn1ZZ3bYzgK;lQ+t{iGTf3ym?D1J`P%!AD96e|K#~oQwQAP zWvK1BW>V2wqLf?imvCTs$^fEnOY(BY7Hm8mi;fLE&!+4L%|p9BZrw7lt^9pc#j(uF zgpw1#Mtp0n+}M3*>ELR98K2l550`DzyT{`hE%WZ*`@Xx_-|xu5j?!WC3YVuRWp;Eu z|Lk8_pSq{@weQ^Hn$<~1n>y19{be7QuB)%jdQnv3@AouPG!AX6e}(nx%JGZCSR~F zem*VI-Znh-Qu*N@E2f1y->fRCjqkm%p(^)7s5)L9-O=bD@}#+|rL;0SzEP)U#JYZ> z?Rq?;<1$_r^geenwz^^Nm4=_ARxBR%=yc1o`#0Y{m~|uMYp=>p3Y7(Xy{DxenVj;h zvH8%c-9A{u_Uxgg*cP From 7c26e844637b54f28dee70d1a79d8fb007e590cd Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 4 Dec 2019 15:17:21 +0100 Subject: [PATCH 011/142] rename Blur() to blur() --- webapp/pages/post/_id/_slug/index.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index 7331daf6d..311b95f04 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -23,7 +23,7 @@ class="bluricon-post" icon="eye-slash" primary - @click.prevent="Blur" + @click.prevent="blur" > Date: Wed, 4 Dec 2019 15:23:16 +0100 Subject: [PATCH 012/142] lint fix --- webapp/components/ContributionForm/ContributionForm.spec.js | 1 - webapp/pages/post/_id/_slug/index.vue | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/webapp/components/ContributionForm/ContributionForm.spec.js b/webapp/components/ContributionForm/ContributionForm.spec.js index 889995595..53057a771 100644 --- a/webapp/components/ContributionForm/ContributionForm.spec.js +++ b/webapp/components/ContributionForm/ContributionForm.spec.js @@ -250,7 +250,6 @@ describe('ContributionForm.vue', () => { await wrapper.find('input[type="checkbox"]').trigger('click') expect(wrapper.find('input[type="checkbox"]').exists()).toBe(true) expect(wrapper.find('.images-set-blur').exists()).toBe(true) - }) }) diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index 311b95f04..e0949498a 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -23,7 +23,7 @@ class="bluricon-post" icon="eye-slash" primary - @click.prevent="blur" + @click.prevent="setBlur" > Date: Thu, 5 Dec 2019 13:17:26 +0100 Subject: [PATCH 013/142] Use readTransaction for non-write transactions --- backend/src/middleware/validation/validationMiddleware.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/middleware/validation/validationMiddleware.js b/backend/src/middleware/validation/validationMiddleware.js index f36458e61..4413b7747 100644 --- a/backend/src/middleware/validation/validationMiddleware.js +++ b/backend/src/middleware/validation/validationMiddleware.js @@ -72,7 +72,7 @@ const validateReview = async (resolve, root, args, context, info) => { const { user, driver } = context if (resourceId === user.id) throw new Error('You cannot review yourself!') const session = driver.session() - const reportReadTxPromise = session.writeTransaction(async txc => { + const reportReadTxPromise = session.readTransaction(async txc => { const validateReviewTransactionResponse = await txc.run( ` MATCH (resource {id: $resourceId}) From f2743c992f4c53df294ada1ef564c9b1dd5769ff Mon Sep 17 00:00:00 2001 From: mattwr18 Date: Thu, 5 Dec 2019 13:18:06 +0100 Subject: [PATCH 014/142] Use transaction function jwt/decode --- backend/src/jwt/decode.js | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/backend/src/jwt/decode.js b/backend/src/jwt/decode.js index 5b7881d20..3b0efea57 100644 --- a/backend/src/jwt/decode.js +++ b/backend/src/jwt/decode.js @@ -11,27 +11,30 @@ export default async (driver, authorizationHeader) => { } catch (err) { return null } - const query = ` - MATCH (user:User {id: $id, deleted: false, disabled: false }) - SET user.lastActiveAt = toString(datetime()) - RETURN user {.id, .slug, .name, .avatar, .email, .role, .disabled, .actorId} - LIMIT 1 - ` const session = driver.session() - let result + const writeTxResultPromise = session.writeTransaction(async txc => { + const updateUserLastActiveTransactionResponse = await txc.run( + ` + MATCH (user:User {id: $id, deleted: false, disabled: false }) + SET user.lastActiveAt = toString(datetime()) + RETURN user {.id, .slug, .name, .avatar, .email, .role, .disabled, .actorId} + LIMIT 1 + `, + { id }, + ) + return updateUserLastActiveTransactionResponse.records.map( + record => record.get('user'), + ) + }) try { - result = await session.run(query, { id }) + const [currentUser] = await writeTxResultPromise + if (!currentUser) return null + return { + token, + ...currentUser, + } } finally { session.close() } - - const [currentUser] = await result.records.map(record => { - return record.get('user') - }) - if (!currentUser) return null - return { - token, - ...currentUser, - } } From de64f1dd4ab850320d3e1e1859a3412f284174f9 Mon Sep 17 00:00:00 2001 From: mattwr18 Date: Thu, 5 Dec 2019 13:43:55 +0100 Subject: [PATCH 015/142] Refactor hashtagsMiddleware updateHashtagsOfPost - Favor transaction functions for production environment - Use one transaction instead of two as we can use optional match to delete potential previous relationships --- .../middleware/hashtags/hashtagsMiddleware.js | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/backend/src/middleware/hashtags/hashtagsMiddleware.js b/backend/src/middleware/hashtags/hashtagsMiddleware.js index 53a8fed20..cbb5e5320 100644 --- a/backend/src/middleware/hashtags/hashtagsMiddleware.js +++ b/backend/src/middleware/hashtags/hashtagsMiddleware.js @@ -2,30 +2,23 @@ import extractHashtags from '../hashtags/extractHashtags' const updateHashtagsOfPost = async (postId, hashtags, context) => { if (!hashtags.length) return - - // We need two Cypher statements, because the 'MATCH' in the 'cypherDeletePreviousRelations' statement - // functions as an 'if'. In case there is no previous relation, the rest of the commands are omitted - // and no new Hashtags and relations will be created. - const cypherDeletePreviousRelations = ` - MATCH (p: Post { id: $postId })-[previousRelations: TAGGED]->(t: Tag) - DELETE previousRelations - RETURN p, t - ` - const cypherCreateNewTagsAndRelations = ` - MATCH (p: Post { id: $postId}) - UNWIND $hashtags AS tagName - MERGE (t: Tag { id: tagName, disabled: false, deleted: false }) - MERGE (p)-[:TAGGED]->(t) - RETURN p, t - ` const session = context.driver.session() + try { - await session.run(cypherDeletePreviousRelations, { - postId, - }) - await session.run(cypherCreateNewTagsAndRelations, { - postId, - hashtags, + await session.writeTransaction(txc => { + return txc.run( + ` + MATCH (post:Post { id: $postId}) + OPTIONAL MATCH (post)-[previousRelations:TAGGED]->(tag:Tag) + DELETE previousRelations + WITH post + UNWIND $hashtags AS tagName + MERGE (tag:Tag {id: tagName, disabled: false, deleted: false }) + MERGE (post)-[:TAGGED]->(tag) + RETURN post, tag + `, + { postId, hashtags }, + ) }) } finally { session.close() From 1827889582e1ddb8749dbcd228f4ab975682e151 Mon Sep 17 00:00:00 2001 From: mattwr18 Date: Thu, 5 Dec 2019 20:42:45 +0100 Subject: [PATCH 016/142] Refactor notificationsMiddleware/locations - start refactoring - locations does not have any automated tests, which makes it more difficult to refactor and have confidence that functionality will not be broken - notificationsMiddleware in progress --- backend/src/jwt/decode.js | 8 +- .../middleware/hashtags/hashtagsMiddleware.js | 2 +- backend/src/middleware/nodes/locations.js | 15 ++-- .../notifications/notificationsMiddleware.js | 83 ++++++------------- .../notificationsMiddleware.spec.js | 6 +- 5 files changed, 39 insertions(+), 75 deletions(-) diff --git a/backend/src/jwt/decode.js b/backend/src/jwt/decode.js index 3b0efea57..41e9d005e 100644 --- a/backend/src/jwt/decode.js +++ b/backend/src/jwt/decode.js @@ -23,14 +23,12 @@ export default async (driver, authorizationHeader) => { `, { id }, ) - return updateUserLastActiveTransactionResponse.records.map( - record => record.get('user'), - ) + return updateUserLastActiveTransactionResponse.records.map(record => record.get('user')) }) try { const [currentUser] = await writeTxResultPromise - if (!currentUser) return null - return { + if (!currentUser) return null + return { token, ...currentUser, } diff --git a/backend/src/middleware/hashtags/hashtagsMiddleware.js b/backend/src/middleware/hashtags/hashtagsMiddleware.js index cbb5e5320..7d8593fd5 100644 --- a/backend/src/middleware/hashtags/hashtagsMiddleware.js +++ b/backend/src/middleware/hashtags/hashtagsMiddleware.js @@ -3,7 +3,7 @@ import extractHashtags from '../hashtags/extractHashtags' const updateHashtagsOfPost = async (postId, hashtags, context) => { if (!hashtags.length) return const session = context.driver.session() - + try { await session.writeTransaction(txc => { return txc.run( diff --git a/backend/src/middleware/nodes/locations.js b/backend/src/middleware/nodes/locations.js index 3e0ca6855..d80d08a9a 100644 --- a/backend/src/middleware/nodes/locations.js +++ b/backend/src/middleware/nodes/locations.js @@ -38,7 +38,7 @@ const createLocation = async (session, mapboxData) => { lng: mapboxData.center && mapboxData.center.length ? mapboxData.center[1] : null, } - let query = + let mutation = 'MERGE (l:Location {id: $id}) ' + 'SET l.name = $nameEN, ' + 'l.nameEN = $nameEN, ' + @@ -53,12 +53,17 @@ const createLocation = async (session, mapboxData) => { 'l.type = $type' if (data.lat && data.lng) { - query += ', l.lat = $lat, l.lng = $lng' + mutation += ', l.lat = $lat, l.lng = $lng' } - query += ' RETURN l.id' + mutation += ' RETURN l.id' - await session.run(query, data) - session.close() + try { + await session.writeTransaction(transaction => { + return transaction.run(mutation, data) + }) + } finally { + session.close() + } } const createOrUpdateLocations = async (userId, locationName, driver) => { diff --git a/backend/src/middleware/notifications/notificationsMiddleware.js b/backend/src/middleware/notifications/notificationsMiddleware.js index ac199a67d..3d6d13790 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.js +++ b/backend/src/middleware/notifications/notificationsMiddleware.js @@ -1,23 +1,22 @@ import extractMentionedUsers from './mentions/extractMentionedUsers' -const postAuthorOfComment = async (comment, { context }) => { - const cypherFindUser = ` - MATCH (user: User)-[:WROTE]->(:Post)<-[:COMMENTS]-(:Comment { id: $commentId }) - RETURN user { .id } - ` +const postAuthorOfComment = async (commentId, { context }) => { const session = context.driver.session() - let result + let postAuthorId try { - result = await session.run(cypherFindUser, { - commentId: comment.id, + postAuthorId = await session.readTransaction(transaction => { + return transaction.run( + ` + MATCH (author:User)-[:WROTE]->(:Post)<-[:COMMENTS]-(:Comment { id: $commentId }) + RETURN author { .id } as authorId + `, + { commentId }, + ) }) + return postAuthorId.records.map(record => record.get('authorId')) } finally { session.close() } - const [postAuthor] = await result.records.map(record => { - return record.get('user') - }) - return postAuthor } const notifyUsers = async (label, id, idsOfUsers, reason, context) => { @@ -90,10 +89,8 @@ const notifyUsers = async (label, id, idsOfUsers, reason, context) => { } const session = context.driver.session() try { - await session.run(cypher, { - id, - idsOfUsers, - reason, + await session.writeTransaction(transaction => { + return transaction.run(cypher, { id, idsOfUsers, reason }) }) } finally { session.close() @@ -102,56 +99,24 @@ const notifyUsers = async (label, id, idsOfUsers, reason, context) => { const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo) => { const idsOfUsers = extractMentionedUsers(args.content) - const post = await resolve(root, args, context, resolveInfo) - - if (post) { - await notifyUsers('Post', post.id, idsOfUsers, 'mentioned_in_post', context) - } - - return post + if (post) return notifyUsers('Post', post.id, idsOfUsers, 'mentioned_in_post', context) } const handleContentDataOfComment = async (resolve, root, args, context, resolveInfo) => { - let idsOfUsers = extractMentionedUsers(args.content) - const comment = await resolve(root, args, context, resolveInfo) - - if (comment) { - const postAuthor = await postAuthorOfComment(comment, { context }) - idsOfUsers = idsOfUsers.filter(id => id !== postAuthor.id) - - await notifyUsers('Comment', comment.id, idsOfUsers, 'mentioned_in_comment', context) - } - - return comment + const { content, id: commentId } = args + let idsOfUsers = extractMentionedUsers(content) + const [postAuthor] = await postAuthorOfComment(commentId, { context }) + idsOfUsers = idsOfUsers.filter(id => id !== postAuthor.id) + if (idsOfUsers && idsOfUsers.length) + await notifyUsers('Comment', commentId, idsOfUsers, 'mentioned_in_comment', context) + if (context.user.id !== postAuthor.id) + await notifyUsers('Comment', commentId, [postAuthor.id], 'commented_on_post', context) } const handleCreateComment = async (resolve, root, args, context, resolveInfo) => { - const comment = await handleContentDataOfComment(resolve, root, args, context, resolveInfo) - - if (comment) { - const cypherFindUser = ` - MATCH (user: User)-[:WROTE]->(:Post)<-[:COMMENTS]-(:Comment { id: $commentId }) - RETURN user { .id } - ` - const session = context.driver.session() - let result - try { - result = await session.run(cypherFindUser, { - commentId: comment.id, - }) - } finally { - session.close() - } - const [postAuthor] = await result.records.map(record => { - return record.get('user') - }) - if (context.user.id !== postAuthor.id) { - await notifyUsers('Comment', comment.id, [postAuthor.id], 'commented_on_post', context) - } - } - - return comment + const comment = await resolve(root, args, context, resolveInfo) + if (comment) return handleContentDataOfComment(resolve, root, args, context, resolveInfo) } export default { diff --git a/backend/src/middleware/notifications/notificationsMiddleware.spec.js b/backend/src/middleware/notifications/notificationsMiddleware.spec.js index 502ddaa8e..6fd94ab69 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.spec.js +++ b/backend/src/middleware/notifications/notificationsMiddleware.spec.js @@ -4,11 +4,7 @@ import { createTestClient } from 'apollo-server-testing' import { neode, getDriver } from '../../bootstrap/neo4j' import createServer from '../../server' -let server -let query -let mutate -let notifiedUser -let authenticatedUser +let server, query, mutate, notifiedUser, authenticatedUser const factory = Factory() const driver = getDriver() const instance = neode() From a62d59741b347141c13126d496b971e2053e5cd7 Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 6 Dec 2019 09:16:14 +0100 Subject: [PATCH 017/142] fix and changes revies, fix lint --- .../ContributionForm/ContributionForm.spec.js | 1 - .../ContributionForm/ContributionForm.vue | 37 +++++-------------- webapp/components/PostCard/PostCard.vue | 3 +- webapp/pages/post/_id/_slug/index.vue | 32 ++++++++-------- 4 files changed, 26 insertions(+), 47 deletions(-) diff --git a/webapp/components/ContributionForm/ContributionForm.spec.js b/webapp/components/ContributionForm/ContributionForm.spec.js index c8d36459e..c84700106 100644 --- a/webapp/components/ContributionForm/ContributionForm.spec.js +++ b/webapp/components/ContributionForm/ContributionForm.spec.js @@ -249,7 +249,6 @@ describe('ContributionForm.vue', () => { wrapper.find(TeaserImage).vm.$emit('addTeaserImage', imageUpload) expect(wrapper.find('.images-set-blur').exists()).toBe(false) await wrapper.find('input[type="checkbox"]').trigger('click') - expect(wrapper.find('input[type="checkbox"]').exists()).toBe(true) expect(wrapper.find('.images-set-blur').exists()).toBe(true) }) }) diff --git a/webapp/components/ContributionForm/ContributionForm.vue b/webapp/components/ContributionForm/ContributionForm.vue index 5d6ff1351..f2ec8327e 100644 --- a/webapp/components/ContributionForm/ContributionForm.vue +++ b/webapp/components/ContributionForm/ContributionForm.vue @@ -10,7 +10,7 @@ -
- +
+
@@ -45,8 +38,8 @@ class="blurImageCheckbox" type="checkbox" id="blur_img" - v-model="checkedBlur" - @change="form.checkbox = checkedBlur" + v-model="blurImage" + @change="form.checkbox = blurImage" /> @@ -223,13 +216,13 @@ export default { contentMin: 3, hashtags: [], elem: null, - checkedBlur: false, + blurImage: false, } }, created() {}, mounted() { if (this.contribution && this.contribution.blurImage === true) { - this.checkedBlur = true + this.blurImage = true } }, computed: { @@ -242,8 +235,8 @@ export default { }, methods: { unBlur() { - if (this.checkedBlur) { - this.checkedBlur = false + if (this.blurImage) { + this.blurImage = false } }, submit() { @@ -335,18 +328,6 @@ export default { - - - diff --git a/webapp/components/PostCard/PostCard.vue b/webapp/components/PostCard/PostCard.vue index d5e65746b..ad5a68388 100644 --- a/webapp/components/PostCard/PostCard.vue +++ b/webapp/components/PostCard/PostCard.vue @@ -5,8 +5,8 @@ :class="{ 'post-card': true, 'disabled-content': post.disabled, - 'post--pinned': isPinned, - 'images-set-blur': post.blurImage, + '--pinned': isPinned, + '--blur-image': post.blurImage, }" > @@ -157,22 +157,26 @@ export default { }, } - diff --git a/webapp/components/TeaserImage/TeaserImage.vue b/webapp/components/TeaserImage/TeaserImage.vue index fbf230660..c4b8d4b31 100644 --- a/webapp/components/TeaserImage/TeaserImage.vue +++ b/webapp/components/TeaserImage/TeaserImage.vue @@ -142,7 +142,7 @@ export default { diff --git a/webapp/components/SearchInput/SearchInput.spec.js b/webapp/components/features/SearchResources/SearchResources.spec.js similarity index 90% rename from webapp/components/SearchInput/SearchInput.spec.js rename to webapp/components/features/SearchResources/SearchResources.spec.js index 8cc8b9459..cc4d230c2 100644 --- a/webapp/components/SearchInput/SearchInput.spec.js +++ b/webapp/components/features/SearchResources/SearchResources.spec.js @@ -1,12 +1,12 @@ import { mount } from '@vue/test-utils' -import SearchInput from './SearchInput.vue' +import SearchResources from './SearchResources.vue' const localVue = global.localVue localVue.filter('truncate', () => 'truncated string') localVue.filter('dateTime', () => Date.now) -describe('SearchInput.vue', () => { +describe('SearchResources.vue', () => { let mocks let propsData @@ -19,7 +19,7 @@ describe('SearchInput.vue', () => { mocks = { $t: () => {}, } - return mount(SearchInput, { mocks, localVue, propsData }) + return mount(SearchResources, { mocks, localVue, propsData }) } it('renders', () => { @@ -27,7 +27,7 @@ describe('SearchInput.vue', () => { }) it('has id "nav-search"', () => { - expect(Wrapper().contains('#nav-search')).toBe(true) + expect(Wrapper().contains('[data-test="search-resources"]')).toBe(true) }) it('defaults to an empty value', () => { @@ -82,9 +82,9 @@ describe('SearchInput.vue', () => { expect(wrapper.emitted().clear.length).toBe(1) }) - it('changes the unprocessedSearchInput as the value changes', () => { + it('changes the unprocessedSearchResources as the value changes', () => { select.trigger('input') - expect(wrapper.vm.unprocessedSearchInput).toBe('abcd') + expect(wrapper.vm.unprocessedSearchResources).toBe('abcd') }) it('searches for the term when enter is pressed', async () => { diff --git a/webapp/components/SearchInput/SearchInput.story.js b/webapp/components/features/SearchResources/SearchResources.story.js similarity index 97% rename from webapp/components/SearchInput/SearchInput.story.js rename to webapp/components/features/SearchResources/SearchResources.story.js index 0ae47e24f..328259917 100644 --- a/webapp/components/SearchInput/SearchInput.story.js +++ b/webapp/components/features/SearchResources/SearchResources.story.js @@ -1,6 +1,6 @@ import { storiesOf } from '@storybook/vue' import { withA11y } from '@storybook/addon-a11y' -import SearchInput from './SearchInput.vue' +import SearchResources from './SearchResources.vue' import helpers from '~/storybook/helpers' helpers.init() @@ -104,7 +104,7 @@ storiesOf('Search Input', module) .addDecorator(withA11y) .addDecorator(helpers.layout) .add('test', () => ({ - components: { SearchInput }, + components: { SearchResources }, store: helpers.store, data: () => ({ results: results, diff --git a/webapp/components/features/SearchResources/SearchResources.vue b/webapp/components/features/SearchResources/SearchResources.vue new file mode 100644 index 000000000..d0be17569 --- /dev/null +++ b/webapp/components/features/SearchResources/SearchResources.vue @@ -0,0 +1,51 @@ + + + diff --git a/webapp/components/SearchInput/SearchHeading.vue b/webapp/components/generic/SearchHeading/SearchHeading.vue similarity index 94% rename from webapp/components/SearchInput/SearchHeading.vue rename to webapp/components/generic/SearchHeading/SearchHeading.vue index e9d5aa662..9a4602980 100644 --- a/webapp/components/SearchInput/SearchHeading.vue +++ b/webapp/components/generic/SearchHeading/SearchHeading.vue @@ -13,4 +13,3 @@ export default { }, } - diff --git a/webapp/components/SearchInput/SearchPost.vue b/webapp/components/generic/SearchPost/SearchPost.vue similarity index 75% rename from webapp/components/SearchInput/SearchPost.vue rename to webapp/components/generic/SearchPost/SearchPost.vue index 6ebbd5084..97108afe8 100644 --- a/webapp/components/SearchInput/SearchPost.vue +++ b/webapp/components/generic/SearchPost/SearchPost.vue @@ -1,5 +1,5 @@