From e31f250ea5e1949f4f08e72fe82622d41ecd85f1 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Jul 2022 18:41:39 +0200 Subject: [PATCH 1/7] env vatiable for CATEGORIES_ACTIVE and switch for categories in contribution form --- webapp/.env.template | 1 + .../ContributionForm/ContributionForm.vue | 32 +++++++++++++++++-- webapp/config/index.js | 1 + 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/webapp/.env.template b/webapp/.env.template index 7373255a9..0a4c3405f 100644 --- a/webapp/.env.template +++ b/webapp/.env.template @@ -4,3 +4,4 @@ PUBLIC_REGISTRATION=false INVITE_REGISTRATION=true WEBSOCKETS_URI=ws://localhost:3000/api/graphql GRAPHQL_URI=http://localhost:4000/ +CATEGORIES_ACTIVE=false \ No newline at end of file diff --git a/webapp/components/ContributionForm/ContributionForm.vue b/webapp/components/ContributionForm/ContributionForm.vue index a06679149..e25dd6b0f 100644 --- a/webapp/components/ContributionForm/ContributionForm.vue +++ b/webapp/components/ContributionForm/ContributionForm.vue @@ -51,6 +51,19 @@ {{ contentLength }} + + + {{ formData.categoryIds.length }} / 3 + +
{{ $t('actions.cancel') }} @@ -69,6 +82,7 @@ import gql from 'graphql-tag' import { mapGetters } from 'vuex' import HcEditor from '~/components/Editor/Editor' import PostMutations from '~/graphql/PostMutations.js' +import CategoriesSelect from '~/components/CategoriesSelect/CategoriesSelect' import ImageUploader from '~/components/ImageUploader/ImageUploader' import links from '~/constants/links.js' import PageParamsLink from '~/components/_new/features/PageParamsLink/PageParamsLink.vue' @@ -78,6 +92,7 @@ export default { HcEditor, ImageUploader, PageParamsLink, + CategoriesSelect, }, props: { contribution: { @@ -86,7 +101,7 @@ export default { }, }, data() { - const { title, content, image } = this.contribution + const { title, content, image, categories } = this.contribution const { sensitive: imageBlurred = false, aspectRatio: imageAspectRatio = null, @@ -94,6 +109,7 @@ export default { } = image || {} return { + categoriesActive: this.$env.CATEGORIES_ACTIVE, links, formData: { title: title || '', @@ -102,11 +118,22 @@ export default { imageAspectRatio, imageType, imageBlurred, + categoryIds: categories ? categories.map((category) => category.id) : [], }, formSchema: { title: { required: true, min: 3, max: 100 }, content: { required: true }, imageBlurred: { required: false }, + categoryIds: { + type: 'array', + required: true, + validator: (_, value = []) => { + if (value.length === 0 || value.length > 3) { + return [new Error(this.$t('common.validations.categories'))] + } + return [] + }, + }, }, loading: false, users: [], @@ -125,7 +152,7 @@ export default { methods: { submit() { let image = null - const { title, content } = this.formData + const { title, content, categoryIds } = this.formData if (this.formData.image) { image = { sensitive: this.formData.imageBlurred, @@ -143,6 +170,7 @@ export default { variables: { title, content, + categoryIds, id: this.contribution.id || null, image, }, diff --git a/webapp/config/index.js b/webapp/config/index.js index 00df85bac..db030e929 100644 --- a/webapp/config/index.js +++ b/webapp/config/index.js @@ -33,6 +33,7 @@ const options = { // Cookies COOKIE_EXPIRE_TIME: process.env.COOKIE_EXPIRE_TIME || 730, // Two years by default COOKIE_HTTPS_ONLY: process.env.COOKIE_HTTPS_ONLY || process.env.NODE_ENV === 'production', // ensure true in production if not set explicitly + CATEGORIES_ACTIVE: process.env.CATEGORIES_ACTIVE === 'true' || false, } const CONFIG = { From 28ddfde0e31d424ef0f48766e7d705bc525f0f28 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Jul 2022 19:02:08 +0200 Subject: [PATCH 2/7] add categories active to .env, save categories on create --- backend/.env.template | 2 ++ backend/src/config/index.js | 1 + backend/src/schema/resolvers/posts.js | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/backend/.env.template b/backend/.env.template index 5858a5d1e..239046dd3 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -28,3 +28,5 @@ AWS_BUCKET= EMAIL_DEFAULT_SENDER="devops@ocelot.social" EMAIL_SUPPORT="devops@ocelot.social" + +CATEGORIES_ACTIVE=false \ No newline at end of file diff --git a/backend/src/config/index.js b/backend/src/config/index.js index 6ad8c578b..7df780cfc 100644 --- a/backend/src/config/index.js +++ b/backend/src/config/index.js @@ -86,6 +86,7 @@ const options = { ORGANIZATION_URL: emails.ORGANIZATION_LINK, PUBLIC_REGISTRATION: env.PUBLIC_REGISTRATION === 'true' || false, INVITE_REGISTRATION: env.INVITE_REGISTRATION !== 'false', // default = true + CATEGORIES_ACTIVE: process.env.CATEGORIES_ACTIVE === 'true' || false, } // Check if all required configs are present diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index d199b6f09..f4faaeb17 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -5,6 +5,7 @@ import { UserInputError } from 'apollo-server' import { mergeImage, deleteImage } from './images/images' import Resolver from './helpers/Resolver' import { filterForMutedUsers } from './helpers/filterForMutedUsers' +import CONFIG from '../../config' const maintainPinnedPosts = (params) => { const pinnedPostFilter = { pinned: true } @@ -76,12 +77,20 @@ export default { }, Mutation: { CreatePost: async (_parent, params, context, _resolveInfo) => { + const { categoryIds } = params const { image: imageInput } = params delete params.categoryIds delete params.image params.id = params.id || uuid() const session = context.driver.session() const writeTxResultPromise = session.writeTransaction(async (transaction) => { + const categoriesCypher = + CONFIG.CATEGORIES_ACTIVE && categoryIds + ? `WITH post + UNWIND $categoryIds AS categoryId + MATCH (category:Category {id: categoryId}) + MERGE (post)-[:CATEGORIZED]->(category)` + : '' const createPostTransactionResponse = await transaction.run( ` CREATE (post:Post) @@ -91,11 +100,13 @@ export default { SET post.clickedCount = 0 SET post.viewedTeaserCount = 0 WITH post + UNWIND $categoryIds AS categoryId MATCH (author:User {id: $userId}) MERGE (post)<-[:WROTE]-(author) + ${categoriesCypher} RETURN post {.*} `, - { userId: context.user.id, params }, + { userId: context.user.id, params, categoryIds }, ) const [post] = createPostTransactionResponse.records.map((record) => record.get('post')) if (imageInput) { @@ -127,7 +138,7 @@ export default { WITH post ` - if (categoryIds && categoryIds.length) { + if (CONFIG.CATEGORIES_ACTIVE && categoryIds && categoryIds.length) { const cypherDeletePreviousRelations = ` MATCH (post:Post { id: $params.id })-[previousRelations:CATEGORIZED]->(category:Category) DELETE previousRelations From 1b2509229c7f6aa0c37338584d592f44c17f7c3d Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Jul 2022 19:22:17 +0200 Subject: [PATCH 3/7] remove bad line in cypher --- backend/src/schema/resolvers/posts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index f4faaeb17..b09bb3edd 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -100,7 +100,6 @@ export default { SET post.clickedCount = 0 SET post.viewedTeaserCount = 0 WITH post - UNWIND $categoryIds AS categoryId MATCH (author:User {id: $userId}) MERGE (post)<-[:WROTE]-(author) ${categoriesCypher} From bc955003f7c33aabe592bee782aca973b4f00cba Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Jul 2022 20:03:00 +0200 Subject: [PATCH 4/7] add optional categories to teaser and post --- webapp/components/PostTeaser/PostTeaser.vue | 21 +++++++++++++++++- webapp/graphql/Fragments.js | 6 ++++++ webapp/pages/post/_id/_slug/index.vue | 24 +++++++++++++++++---- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/webapp/components/PostTeaser/PostTeaser.vue b/webapp/components/PostTeaser/PostTeaser.vue index 949c7032e..a973ca31f 100644 --- a/webapp/components/PostTeaser/PostTeaser.vue +++ b/webapp/components/PostTeaser/PostTeaser.vue @@ -26,7 +26,19 @@ class="footer" v-observe-visibility="(isVisible, entry) => visibilityChanged(isVisible, entry, post.id)" > -
+
+ +
+
{}, }, }, + data() { + return { + categoriesActive: this.$env.CATEGORIES_ACTIVE, + } + }, mounted() { const { image } = this.post if (!image) return diff --git a/webapp/graphql/Fragments.js b/webapp/graphql/Fragments.js index 7b05e2369..b67851873 100644 --- a/webapp/graphql/Fragments.js +++ b/webapp/graphql/Fragments.js @@ -78,6 +78,12 @@ export const tagsCategoriesAndPinnedFragment = gql` tags { id } + categories { + id + slug + name + icon + } pinnedBy { id name diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index b1ca870d7..d02a448da 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -44,6 +44,19 @@

{{ post.title }}

+ +
+ + + + +
+
@@ -91,6 +104,7 @@