refactor(backend): category seed (#8505)

* define ids and slugs in categories, check for existing ids, only seed the new ids

* seed categories respecting existing categories

---------

Co-authored-by: Ulf Gebhardt <ulf.gebhardt@webcraft-media.de>
This commit is contained in:
Moriz Wahl 2025-05-08 22:27:41 +02:00 committed by GitHub
parent 3f4d648562
commit fbec8288b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 78 additions and 51 deletions

View File

@ -22,6 +22,8 @@ FROM base AS build
COPY . .
ONBUILD COPY ./branding/constants/ src/config/tmp
ONBUILD RUN tools/replace-constants.sh
# copy categories to brand them (use yarn prod:db:data:categories)
ONBUILD COPY branding/constants/ src/constants/
ONBUILD COPY ./branding/email/ src/middleware/helpers/email/
ONBUILD COPY ./branding/middlewares/ src/middleware/branding/
ONBUILD COPY ./branding/data/ src/db/data

View File

@ -24,7 +24,8 @@
"db:migrate": "migrate --compiler 'ts:./src/db/compiler.ts' --migrations-dir ./src/db/migrations --store ./src/db/migrate/store.ts",
"db:migrate:create": "migrate --compiler 'ts:./src/db/compiler.ts' --migrations-dir ./src/db/migrations --template-file ./src/db/migrate/template.ts --date-format 'yyyymmddHHmmss' create",
"prod:migrate": "migrate --migrations-dir ./build/src/db/migrations --store ./build/src/db/migrate/store.js",
"prod:db:data:branding": "node build/src/db/data-branding.js"
"prod:db:data:branding": "node build/src/db/data-branding.js",
"prod:db:data:categories": "node build/src/db/categories.js"
},
"dependencies": {
"@sentry/node": "^5.15.4",

View File

@ -5,98 +5,116 @@ export const CATEGORIES_MAX = 3
export const categories = [
{
icon: 'networking',
id: 'cat0',
slug: 'networking',
name: 'networking',
description: 'Kooperation, Aktionsbündnisse, Solidarität, Hilfe',
},
{
icon: 'home',
id: 'cat1',
slug: 'home',
name: 'home',
description: 'Bauen, Lebensgemeinschaften, Tiny Houses, Gemüsegarten',
},
{
icon: 'energy',
id: 'cat2',
slug: 'energy',
name: 'energy',
description: 'Öl, Gas, Kohle, Wind, Wasserkraft, Biogas, Atomenergie, ...',
},
{
icon: 'psyche',
id: 'cat3',
slug: 'psyche',
name: 'psyche',
description: 'Seele, Gefühle, Glück',
},
{
icon: 'movement',
id: 'cat4',
slug: 'body-and-excercise',
name: 'body-and-excercise',
description: 'Sport, Yoga, Massage, Tanzen, Entspannung',
},
{
icon: 'balance-scale',
id: 'cat5',
slug: 'law',
name: 'law',
description: 'Menschenrechte, Gesetze, Verordnungen',
},
{
icon: 'finance',
id: 'cat6',
slug: 'finance',
name: 'finance',
description: 'Geld, Finanzsystem, Alternativwährungen, ...',
},
{
icon: 'child',
id: 'cat7',
slug: 'children',
name: 'children',
description: 'Familie, Pädagogik, Schule, Prägung',
},
{
icon: 'mobility',
id: 'cat8',
slug: 'mobility',
name: 'mobility',
description: 'Reise, Verkehr, Elektromobilität',
},
{
icon: 'shopping-cart',
id: 'cat9',
slug: 'economy',
name: 'economy',
description: 'Handel, Konsum, Marketing, Lebensmittel, Lieferketten, ...',
},
{
icon: 'peace',
id: 'cat10',
slug: 'peace',
name: 'peace',
description: 'Krieg, Militär, soziale Verteidigung, Waffen, Cyberattacken',
},
{
icon: 'politics',
id: 'cat11',
slug: 'politics',
name: 'politics',
description: 'Demokratie, Mitbestimmung, Wahlen, Korruption, Parteien',
},
{
icon: 'nature',
id: 'cat12',
slug: 'nature',
name: 'nature',
description: 'Tiere, Pflanzen, Landwirtschaft, Ökologie, Artenvielfalt',
},
{
icon: 'science',
id: 'cat13',
slug: 'science',
name: 'science',
description: 'Bildung, Hochschule, Publikationen, ...',
},
{
icon: 'health',
id: 'cat14',
slug: 'health',
name: 'health',
description: 'Medizin, Ernährung, WHO, Impfungen, Schadstoffe, ...',
},
{
icon: 'media',
id: 'cat15',
slug: 'it-and-media',
name: 'it-and-media',
description:
'Nachrichten, Manipulation, Datenschutz, Überwachung, Datenkraken, AI, Software, Apps',
},
{
icon: 'spirituality',
id: 'cat16',
slug: 'spirituality',
name: 'spirituality',
description: 'Religion, Werte, Ethik',
},
{
icon: 'culture',
id: 'cat17',
slug: 'culture',
name: 'culture',
description: 'Kunst, Theater, Musik, Fotografie, Film',
},
{
icon: 'miscellaneous',
id: 'cat18',
slug: 'miscellaneous',
name: 'miscellaneous',
description: '',
},
]

View File

@ -4,7 +4,7 @@ import type { Driver } from 'neo4j-driver'
export const query =
(driver: Driver) =>
async ({ query, variables = {} }: { query: string; variables: object }) => {
async ({ query, variables = {} }: { query: string; variables?: object }) => {
const session = driver.session()
const result = session.readTransaction(async (transaction) => {
@ -21,7 +21,7 @@ export const query =
export const write =
(driver: Driver) =>
async ({ query, variables = {} }: { query: string; variables: object }) => {
async ({ query, variables = {} }: { query: string; variables?: object }) => {
const session = driver.session()
const result = session.writeTransaction(async (transaction) => {

View File

@ -1,38 +1,44 @@
/* eslint-disable @typescript-eslint/no-floating-promises */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable @typescript-eslint/require-await */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { categories } from '@constants/categories'
import databaseContext from '@context/database'
import { getDriver } from './neo4j'
const { query, write, driver } = databaseContext()
const createCategories = async () => {
const driver = getDriver()
const session = driver.session()
const createCategoriesTxResultPromise = session.writeTransaction(async (txc) => {
categories.forEach(({ icon, name }, index) => {
const id = `cat${index + 1}`
txc.run(
`MERGE (c:Category {
icon: "${icon}",
slug: "${name}",
name: "${name}",
id: "${id}",
createdAt: toString(datetime())
})`,
)
})
const result = await query({
query: 'MATCH (category:Category) RETURN category { .* }',
})
try {
await createCategoriesTxResultPromise
console.log('Successfully created categories!') // eslint-disable-line no-console
// eslint-disable-next-line no-catch-all/no-catch-all
} catch (error) {
console.log(`Error creating categories: ${error}`) // eslint-disable-line no-console
} finally {
session.close()
driver.close()
}
const existingCategories = result.records.map((r) => r.get('category'))
const existingCategoryIds = existingCategories.map((c) => c.id)
const newCategories = categories.filter((c) => !existingCategoryIds.includes(c.id))
await write({
query: `UNWIND $newCategories AS map
CREATE (category:Category)
SET category = map
SET category.createdAt = toString(datetime())`,
variables: {
newCategories,
},
})
const categoryIds = categories.map((c) => c.id)
await write({
query: `MATCH (category:Category)
WHERE NOT category.id IN $categoryIds
DETACH DELETE category`,
variables: {
categoryIds,
},
})
// eslint-disable-next-line no-console
console.log('Successfully created categories!')
await driver.close()
}
;(async function () {