diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index e2346a4a5..1b7ed87bc 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,7 +1,7 @@
name: gradido publish CI
on:
- push:
+ pull_request:
branches:
- master
@@ -10,7 +10,7 @@ jobs:
# JOB: DOCKER BUILD PRODUCTION FRONTEND ######################################
##############################################################################
build_production_frontend:
- if: startsWith(github.event.head_commit.message, 'chore(release):')
+ if: startsWith(github.event.pull_request.title, 'chore(release):')
name: Docker Build Production - Frontend
runs-on: ubuntu-latest
#needs: [nothing]
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0cca591bc..1ef3c24bd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,8 +4,26 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
+#### [v2.7.4](https://github.com/gradido/gradido/compare/v2.7.3...v2.7.4)
+
+- feat(workflow): update .env.dist in deploy and make install script more idempotent [`#3593`](https://github.com/gradido/gradido/pull/3593)
+- feat(admin): load moderator names for contribution list [`#3599`](https://github.com/gradido/gradido/pull/3599)
+- fix(other): email mime types [`#3601`](https://github.com/gradido/gradido/pull/3601)
+- fix(database): use connection pool for drizzle orm [`#3600`](https://github.com/gradido/gradido/pull/3600)
+- feat(admin): make deleted contributions better recognisable with Deuteranopie [`#3597`](https://github.com/gradido/gradido/pull/3597)
+- fix(workflow): rewrite sort.sh as sortLocales.ts [`#3598`](https://github.com/gradido/gradido/pull/3598)
+- refactor(database): add drizzleOrm, use it in openaiThreads [`#3595`](https://github.com/gradido/gradido/pull/3595)
+- fix(other): fix biome config [`#3592`](https://github.com/gradido/gradido/pull/3592)
+- feat(other): reduce github worker count [`#3591`](https://github.com/gradido/gradido/pull/3591)
+- fix(other): removed phantom line, aligned env and compose [`#3570`](https://github.com/gradido/gradido/pull/3570)
+- feat(dlt): migrate database transaction to dlt transactions [`#3571`](https://github.com/gradido/gradido/pull/3571)
+- feat(dlt): add inspector as submodule, update nginx config to serve inspector and gradido node [`#3566`](https://github.com/gradido/gradido/pull/3566)
+- chore(release): v2.7.3 [`#3590`](https://github.com/gradido/gradido/pull/3590)
+
#### [v2.7.3](https://github.com/gradido/gradido/compare/v2.7.2...v2.7.3)
+> 4 December 2025
+
- feat(admin): show user registered at in admin [`#3589`](https://github.com/gradido/gradido/pull/3589)
- feat(backend): 3573 feature introduce distributed semaphore base on redis [`#3580`](https://github.com/gradido/gradido/pull/3580)
- fix(workflow): make deployment install script more robust [`#3588`](https://github.com/gradido/gradido/pull/3588)
diff --git a/admin/.env.template b/admin/.env.template
index 24725f279..4a65b5a35 100644
--- a/admin/.env.template
+++ b/admin/.env.template
@@ -1,5 +1,3 @@
-CONFIG_VERSION=$ADMIN_CONFIG_VERSION
-
COMMUNITY_HOST=$COMMUNITY_HOST
URL_PROTOCOL=$URL_PROTOCOL
WALLET_AUTH_PATH=$WALLET_AUTH_PATH
diff --git a/admin/package.json b/admin/package.json
index e7c6e70d0..61bbb21ac 100644
--- a/admin/package.json
+++ b/admin/package.json
@@ -3,7 +3,7 @@
"description": "Administration Interface for Gradido",
"main": "index.js",
"author": "Gradido Academy - https://www.gradido.net",
- "version": "2.7.3",
+ "version": "2.7.4",
"license": "Apache-2.0",
"scripts": {
"dev": "vite",
diff --git a/admin/src/components/RowDetails.vue b/admin/src/components/RowDetails.vue
index 9715ef158..97858c22b 100644
--- a/admin/src/components/RowDetails.vue
+++ b/admin/src/components/RowDetails.vue
@@ -6,7 +6,7 @@
:icon="type === 'PageCreationConfirm' ? 'x' : 'eye-slash-fill'"
aria-label="Help"
>
- {{ $t('hide_details') }} {{ row.item.user.firstName }} {{ row.item.user.lastName }}
+ {{ $t('hide_details') }}
diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue
index 4e29b4241..46a1651a1 100644
--- a/admin/src/components/Tables/OpenCreationsTable.vue
+++ b/admin/src/components/Tables/OpenCreationsTable.vue
@@ -34,11 +34,20 @@
+
+
+ {{ row.item.user.firstName }} {{ row.item.user.lastName }}
+
+
+ {{ row.item.user.alias }}
+
+
+
{{ row.value }}
-
+
- {{ $t('moderator.memo-modified') }}
+ {{ getMemoComment(row.item) }}
@@ -140,6 +149,7 @@
import RowDetails from '../RowDetails'
import EditCreationFormular from '../EditCreationFormular'
import ContributionMessagesList from '../ContributionMessages/ContributionMessagesList'
+import { useDateFormatter } from '@/composables/useDateFormatter'
const iconMap = {
IN_PROGRESS: 'question-square',
@@ -195,6 +205,7 @@ export default {
this.removeClipboardListener()
},
methods: {
+ ...useDateFormatter(),
myself(item) {
return item.userId === this.$store.state.moderator.id
},
@@ -235,6 +246,36 @@ export default {
this.creationUserData = row.item
}
},
+ isAddCommentToMemo(item) {
+ return item.closedBy > 0 || item.moderatorId > 0 || item.updatedBy > 0
+ },
+ getMemoComment(item) {
+ let comment = ''
+ if (item.closedBy > 0) {
+ if (item.contributionStatus === 'CONFIRMED') {
+ comment = this.$t('contribution.confirmedBy', { name: item.closedByUserName })
+ } else if (item.contributionStatus === 'DENIED') {
+ comment = this.$t('contribution.deniedBy', { name: item.closedByUserName })
+ } else if (item.contributionStatus === 'DELETED') {
+ comment = this.$t('contribution.deletedBy', { name: item.closedByUserName })
+ }
+ }
+
+ if (item.updatedBy > 0) {
+ if (comment.length) {
+ comment += ' | '
+ }
+ comment += this.$t('moderator.memo-modified', { name: item.updatedByUserName })
+ }
+
+ if (item.moderatorId > 0) {
+ if (comment.length) {
+ comment += ' | '
+ }
+ comment += this.$t('contribution.createdBy', { name: item.moderatorUserName })
+ }
+ return comment
+ },
addClipboardListener() {
document.addEventListener('copy', this.handleCopy)
},
diff --git a/admin/src/composables/useDateFormatter.js b/admin/src/composables/useDateFormatter.js
index 8f3c85bfe..6e062b3e9 100644
--- a/admin/src/composables/useDateFormatter.js
+++ b/admin/src/composables/useDateFormatter.js
@@ -1,10 +1,14 @@
export const useDateFormatter = () => {
const formatDateFromDateTime = (datetimeString) => {
- if (!datetimeString || !datetimeString?.includes('T')) return datetimeString
+ if (!datetimeString || !datetimeString?.includes('T')) {
+ return datetimeString
+ }
return datetimeString.split('T')[0]
}
+ const formatDateOrDash = (value) => (value ? new Date(value).toLocaleDateString() : '—')
return {
formatDateFromDateTime,
+ formatDateOrDash,
}
}
diff --git a/admin/src/graphql/adminListContributions.graphql b/admin/src/graphql/adminListContributions.graphql
index 57c26c10a..e2b6417d1 100644
--- a/admin/src/graphql/adminListContributions.graphql
+++ b/admin/src/graphql/adminListContributions.graphql
@@ -19,19 +19,18 @@ query adminListContributions(
}
amount
memo
- createdAt
+ closedAt
+ closedBy
+ closedByUserName
contributionDate
- confirmedAt
- confirmedBy
+ createdAt
updatedAt
- updatedBy
+ updatedBy
+ updatedByUserName
contributionStatus
messagesCount
- deniedAt
- deniedBy
- deletedAt
- deletedBy
moderatorId
+ moderatorUserName
userId
resubmissionAt
}
diff --git a/admin/src/locales/de.json b/admin/src/locales/de.json
index bf02b825b..d36d53576 100644
--- a/admin/src/locales/de.json
+++ b/admin/src/locales/de.json
@@ -16,6 +16,12 @@
"back": "zurück",
"change_user_role": "Nutzerrolle ändern",
"close": "Schließen",
+ "contribution": {
+ "confirmedBy": "Bestätigt von {name}.",
+ "createdBy": "Erstellt von {name}.",
+ "deletedBy": "Gelöscht von {name}.",
+ "deniedBy": "Abgelehnt von {name}."
+ },
"contributionLink": {
"amount": "Betrag",
"changeSaved": "Änderungen gespeichert",
@@ -49,6 +55,7 @@
},
"contributions": {
"all": "Alle",
+ "closed": "Geschlossen",
"confirms": "Bestätigt",
"deleted": "Gelöscht",
"denied": "Abgelehnt",
@@ -166,7 +173,7 @@
"moderator": {
"history": "Die Daten wurden geändert. Dies sind die alten Daten.",
"memo": "Text ändern",
- "memo-modified": "Text vom Moderator bearbeitet.",
+ "memo-modified": "Text von {name} bearbeitet.",
"memo-tooltip": "Den Beitragstext bearbeiten",
"message": "Nachricht",
"message-tooltip": "Nachricht an Benutzer schreiben",
diff --git a/admin/src/locales/en.json b/admin/src/locales/en.json
index b4ef9c534..b0db604cc 100644
--- a/admin/src/locales/en.json
+++ b/admin/src/locales/en.json
@@ -16,6 +16,12 @@
"back": "back",
"change_user_role": "Change user role",
"close": "Close",
+ "contribution": {
+ "confirmedBy": "Confirmed by {name}.",
+ "createdBy": "Created by {name}.",
+ "deletedBy": "Deleted by {name}.",
+ "deniedBy": "Rejected by {name}."
+ },
"contributionLink": {
"amount": "Amount",
"changeSaved": "Changes saved",
@@ -49,6 +55,7 @@
},
"contributions": {
"all": "All",
+ "closed": "Closed",
"confirms": "Confirmed",
"deleted": "Deleted",
"denied": "Rejected",
@@ -166,7 +173,7 @@
"moderator": {
"history": "The data has been changed. This is the old data.",
"memo": "Edit text",
- "memo-modified": "Text edited by moderator",
+ "memo-modified": "Text edited by {name}",
"memo-tooltip": "Edit the text of the contribution",
"message": "Message",
"message-tooltip": "Write message to user",
diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue
index 74588f9f4..ea8414296 100644
--- a/admin/src/pages/CreationConfirm.vue
+++ b/admin/src/pages/CreationConfirm.vue
@@ -108,6 +108,7 @@ import { confirmContribution } from '../graphql/confirmContribution'
import { denyContribution } from '../graphql/denyContribution'
import { getContribution } from '../graphql/getContribution'
import { useAppToast } from '@/composables/useToast'
+import { useDateFormatter } from '@/composables/useDateFormatter'
import CONFIG from '@/config'
const FILTER_TAB_MAP = [
@@ -134,9 +135,10 @@ const query = ref('')
const noHashtag = ref(null)
const hideResubmissionModel = ref(true)
-const formatDateOrDash = (value) => (value ? new Date(value).toLocaleDateString() : '—')
+const { formatDateOrDash } = useDateFormatter()
const baseFields = {
+ name: { key: 'name', label: t('name'), class: 'no-select' },
firstName: { key: 'user.firstName', label: t('firstname'), class: 'no-select' },
lastName: { key: 'user.lastName', label: t('lastname'), class: 'no-select' },
amount: { key: 'amount', label: t('creation'), formatter: (value) => value + ' GDD' },
@@ -153,13 +155,12 @@ const baseFields = {
class: 'no-select',
formatter: formatDateOrDash,
},
- confirmedAt: {
- key: 'confirmedAt',
- label: t('contributions.confirms'),
+ closedAt: {
+ key: 'closedAt',
+ label: t('contributions.closed'),
class: 'no-select',
formatter: formatDateOrDash,
},
- confirmedBy: { key: 'confirmedBy', label: t('moderator.moderator'), class: 'no-select' },
}
const fields = computed(
@@ -169,70 +170,52 @@ const fields = computed(
[
{ key: 'bookmark', label: t('delete') },
{ key: 'deny', label: t('deny') },
- baseFields.firstName,
- baseFields.lastName,
+ baseFields.name,
baseFields.amount,
baseFields.memo,
baseFields.contributionDate,
- { key: 'moderatorId', label: t('moderator.moderator'), class: 'no-select' },
{ key: 'editCreation', label: t('details') },
{ key: 'confirm', label: t('save') },
],
// confirmed contributions
[
- baseFields.firstName,
- baseFields.lastName,
+ baseFields.name,
baseFields.amount,
baseFields.memo,
baseFields.contributionDate,
baseFields.createdAt,
- baseFields.confirmedAt,
- baseFields.confirmedBy,
+ baseFields.closedAt,
{ key: 'chatCreation', label: t('details') },
],
// denied contributions
[
- baseFields.firstName,
- baseFields.lastName,
+ baseFields.name,
baseFields.amount,
baseFields.memo,
baseFields.contributionDate,
baseFields.createdAt,
- {
- key: 'deniedAt',
- label: t('contributions.denied'),
- formatter: formatDateOrDash,
- },
- { key: 'deniedBy', label: t('moderator.moderator') },
+ baseFields.closedAt,
{ key: 'chatCreation', label: t('details') },
],
// deleted contributions
[
- baseFields.firstName,
- baseFields.lastName,
+ baseFields.name,
baseFields.amount,
baseFields.memo,
baseFields.contributionDate,
baseFields.createdAt,
- {
- key: 'deletedAt',
- label: t('contributions.deleted'),
- formatter: formatDateOrDash,
- },
- { key: 'deletedBy', label: t('moderator.moderator') },
+ baseFields.closedAt,
{ key: 'chatCreation', label: t('details') },
],
// all contributions
[
{ key: 'contributionStatus', label: t('status') },
- baseFields.firstName,
- baseFields.lastName,
+ baseFields.name,
baseFields.amount,
baseFields.memo,
baseFields.contributionDate,
baseFields.createdAt,
- baseFields.confirmedAt,
- baseFields.confirmedBy,
+ baseFields.closedAt,
{ key: 'chatCreation', label: t('details') },
],
][tabIndex.value],
diff --git a/backend/.env.template b/backend/.env.template
index 98090546d..71a3b049f 100644
--- a/backend/.env.template
+++ b/backend/.env.template
@@ -1,5 +1,3 @@
-# must match the CONFIG_VERSION.EXPECTED definition in scr/config/index.ts
-
# Server
JWT_SECRET=$JWT_SECRET
JWT_EXPIRES_IN=$JWT_EXPIRES_IN
diff --git a/backend/package.json b/backend/package.json
index 9420a155a..fa2bc9bb3 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "backend",
- "version": "2.7.3",
+ "version": "2.7.4",
"private": false,
"description": "Gradido unified backend providing an API-Service for Gradido Transactions",
"repository": "https://github.com/gradido/gradido/backend",
diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts
index 49a3c0be4..4d69ecf26 100644
--- a/backend/src/graphql/model/Contribution.ts
+++ b/backend/src/graphql/model/Contribution.ts
@@ -1,6 +1,6 @@
+import { ContributionStatus } from '@enum/ContributionStatus'
import { Contribution as DbContribution } from 'database'
import { Field, Int, ObjectType } from 'type-graphql'
-
import { UnconfirmedContribution } from './UnconfirmedContribution'
@ObjectType()
@@ -8,6 +8,7 @@ export class Contribution extends UnconfirmedContribution {
constructor(dbContribution: DbContribution) {
super(dbContribution)
this.createdAt = dbContribution.createdAt
+ this.moderatorId = dbContribution.moderatorId
this.confirmedAt = dbContribution.confirmedAt
this.confirmedBy = dbContribution.confirmedBy
this.contributionDate = dbContribution.contributionDate
@@ -19,11 +20,36 @@ export class Contribution extends UnconfirmedContribution {
this.updatedAt = dbContribution.updatedAt
this.updatedBy = dbContribution.updatedBy
this.resubmissionAt = dbContribution.resubmissionAt
+ if (ContributionStatus.CONFIRMED === dbContribution.contributionStatus) {
+ this.closedAt = dbContribution.confirmedAt
+ this.closedBy = dbContribution.confirmedBy
+ } else if (ContributionStatus.DELETED === dbContribution.contributionStatus) {
+ this.closedAt = dbContribution.deletedAt
+ this.closedBy = dbContribution.deletedBy
+ } else if (ContributionStatus.DENIED === dbContribution.contributionStatus) {
+ this.closedAt = dbContribution.deniedAt
+ this.closedBy = dbContribution.deniedBy
+ }
}
+ @Field(() => Date, { nullable: true })
+ closedAt?: Date | null
+
+ @Field(() => Int, { nullable: true })
+ closedBy?: number | null
+
+ @Field(() => String, { nullable: true })
+ closedByUserName?: string | null
+
@Field(() => Date)
createdAt: Date
+ @Field(() => Int, { nullable: true })
+ moderatorId: number | null
+
+ @Field(() => String, { nullable: true })
+ moderatorUserName?: string | null
+
@Field(() => Date, { nullable: true })
confirmedAt: Date | null
@@ -48,6 +74,9 @@ export class Contribution extends UnconfirmedContribution {
@Field(() => Int, { nullable: true })
updatedBy: number | null
+ @Field(() => String, { nullable: true })
+ updatedByUserName?: string | null
+
@Field(() => Date)
contributionDate: Date
diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts
index b18af5c39..9b588158e 100644
--- a/backend/src/graphql/resolver/ContributionResolver.ts
+++ b/backend/src/graphql/resolver/ContributionResolver.ts
@@ -23,6 +23,7 @@ import {
Contribution as DbContribution,
Transaction as DbTransaction,
User as DbUser,
+ findUserNamesByIds,
getLastTransaction,
UserContact,
} from 'database'
@@ -348,6 +349,7 @@ export class ContributionResolver {
): Promise {
// Check if only count was requested (without contributionList)
const fields = Object.keys(extractGraphQLFields(info))
+ // console.log(`fields: ${fields}`)
const countOnly: boolean = fields.includes('contributionCount') && fields.length === 1
// check if related user was requested
const userRequested =
@@ -370,8 +372,25 @@ export class ContributionResolver {
},
countOnly,
)
+ const result = new ContributionListResult(count, dbContributions)
- return new ContributionListResult(count, dbContributions)
+ const uniqueUserIds = new Set()
+ const addIfExist = (userId?: number | null) => (userId ? uniqueUserIds.add(userId) : null)
+
+ for (const contribution of result.contributionList) {
+ addIfExist(contribution.updatedBy)
+ addIfExist(contribution.moderatorId)
+ addIfExist(contribution.closedBy)
+ }
+ const users = await findUserNamesByIds(Array.from(uniqueUserIds))
+ const getNameById = (userId?: number | null) => (userId ? (users.get(userId) ?? null) : null)
+
+ for (const contribution of result.contributionList) {
+ contribution.updatedByUserName = getNameById(contribution.updatedBy)
+ contribution.moderatorUserName = getNameById(contribution.moderatorId)
+ contribution.closedByUserName = getNameById(contribution.closedBy)
+ }
+ return result
}
@Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION])
diff --git a/backend/src/graphql/resolver/util/findContributions.ts b/backend/src/graphql/resolver/util/findContributions.ts
index 5fad940f5..187bb7b53 100644
--- a/backend/src/graphql/resolver/util/findContributions.ts
+++ b/backend/src/graphql/resolver/util/findContributions.ts
@@ -66,6 +66,10 @@ export const findContributions = async (
if (relations?.user) {
qb.orWhere('user.first_name LIKE :firstName', { firstName: queryString })
.orWhere('user.last_name LIKE :lastName', { lastName: queryString })
+ .orWhere('user.alias LIKE :alias', { alias: queryString })
+ .orWhere("LOWER(CONCAT(user.first_name, ' ', user.last_name)) LIKE LOWER(:fullName)", {
+ fullName: queryString.toLowerCase(),
+ })
.orWhere('emailContact.email LIKE :emailContact', { emailContact: queryString })
.orWhere({ memo: Like(queryString) })
}
diff --git a/config-schema/package.json b/config-schema/package.json
index 4bdb30cdc..fa4e30255 100644
--- a/config-schema/package.json
+++ b/config-schema/package.json
@@ -1,6 +1,6 @@
{
"name": "config-schema",
- "version": "2.7.3",
+ "version": "2.7.4",
"description": "Gradido Config for validate config",
"main": "./build/index.js",
"types": "./src/index.ts",
diff --git a/core/package.json b/core/package.json
index 467a6ed46..207c1558c 100644
--- a/core/package.json
+++ b/core/package.json
@@ -1,6 +1,6 @@
{
"name": "core",
- "version": "2.7.3",
+ "version": "2.7.4",
"description": "Gradido Core Code, High-Level Shared Code, with dependencies on other modules",
"main": "./build/index.js",
"types": "./src/index.ts",
diff --git a/core/src/emails/sendEmailTranslated.ts b/core/src/emails/sendEmailTranslated.ts
index 104bbe85f..8ed67f272 100644
--- a/core/src/emails/sendEmailTranslated.ts
+++ b/core/src/emails/sendEmailTranslated.ts
@@ -77,34 +77,46 @@ export const sendEmailTranslated = async ({
...receiver,
attachments: [
{
- // filename: 'gradido-header.jpeg',
+ filename: 'gradido-header.jpeg',
content: gradidoHeader,
cid: 'gradidoheader',
+ contentType: 'image/jpeg',
+ contentDisposition: 'inline',
},
{
- // filename: 'facebook-icon.png',
+ filename: 'facebook-icon.png',
content: facebookIcon,
cid: 'facebookicon',
+ contentType: 'image/png',
+ contentDisposition: 'inline',
},
{
- // filename: 'telegram-icon.png',
+ filename: 'telegram-icon.png',
content: telegramIcon,
cid: 'telegramicon',
+ contentType: 'image/png',
+ contentDisposition: 'inline',
},
{
- // filename: 'twitter-icon.png',
+ filename: 'twitter-icon.png',
content: twitterIcon,
cid: 'twittericon',
+ contentType: 'image/png',
+ contentDisposition: 'inline',
},
{
- // filename: 'youtube-icon.png',
+ filename: 'youtube-icon.png',
content: youtubeIcon,
cid: 'youtubeicon',
+ contentType: 'image/png',
+ contentDisposition: 'inline',
},
{
- // filename: 'chatbox-icon.png',
+ filename: 'chatbox-icon.png',
content: chatboxIcon,
cid: 'chatboxicon',
+ contentType: 'image/png',
+ contentDisposition: 'inline',
},
],
},
diff --git a/database/.env.template b/database/.env.template
index b5aebba8f..48343a569 100644
--- a/database/.env.template
+++ b/database/.env.template
@@ -1,5 +1,3 @@
-CONFIG_VERSION=$DATABASE_CONFIG_VERSION
-
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=$DB_USER
diff --git a/database/migration/index.ts b/database/migration/index.ts
index 2c84fb594..62d1f1107 100644
--- a/database/migration/index.ts
+++ b/database/migration/index.ts
@@ -25,7 +25,7 @@ const run = async (command: string) => {
host: ${CONFIG.DB_HOST}
port: ${CONFIG.DB_PORT}
user: ${CONFIG.DB_USER}
- password: ${CONFIG.DB_PASSWORD.slice(-2)}
+ password: last 2 character: ${CONFIG.DB_PASSWORD.slice(-2)}
database: ${CONFIG.DB_DATABASE}`,
)
}
diff --git a/database/package.json b/database/package.json
index ae578809c..dcefe2b53 100644
--- a/database/package.json
+++ b/database/package.json
@@ -1,6 +1,6 @@
{
"name": "database",
- "version": "2.7.3",
+ "version": "2.7.4",
"description": "Gradido Database Tool to execute database migrations",
"main": "./build/index.js",
"types": "./src/index.ts",
diff --git a/database/src/AppDatabase.ts b/database/src/AppDatabase.ts
index e35043991..63507b4ff 100644
--- a/database/src/AppDatabase.ts
+++ b/database/src/AppDatabase.ts
@@ -1,7 +1,7 @@
import { drizzle, MySql2Database } from 'drizzle-orm/mysql2'
import Redis from 'ioredis'
import { getLogger } from 'log4js'
-import { Connection, createConnection } from 'mysql2/promise'
+import { Connection, createConnection, createPool, Pool } from 'mysql2/promise'
import { DataSource as DBDataSource, FileLogger } from 'typeorm'
import { latestDbVersion } from '.'
import { CONFIG } from './config'
@@ -14,7 +14,7 @@ export class AppDatabase {
private static instance: AppDatabase
private dataSource: DBDataSource | undefined
private drizzleDataSource: MySql2Database | undefined
- private drizzleConnection: Connection | undefined
+ private drizzlePool: Pool | undefined
private redisClient: Redis | undefined
/**
@@ -48,10 +48,10 @@ export class AppDatabase {
}
public getDrizzleDataSource(): MySql2Database {
- if (!this.drizzleDataSource) {
- throw new Error('Drizzle connection not initialized')
+ if (!this.drizzlePool) {
+ throw new Error('Drizzle connection pool not initialized')
}
- return this.drizzleDataSource
+ return drizzle({ client: this.drizzlePool })
}
// create database connection, initialize with automatic retry and check for correct database version
@@ -106,22 +106,25 @@ export class AppDatabase {
logger.info('Redis status=', this.redisClient.status)
if (!this.drizzleDataSource) {
- this.drizzleConnection = await createConnection({
+ this.drizzlePool = createPool({
host: CONFIG.DB_HOST,
user: CONFIG.DB_USER,
password: CONFIG.DB_PASSWORD,
database: CONFIG.DB_DATABASE,
port: CONFIG.DB_PORT,
+ waitForConnections: true,
+ connectionLimit: 20,
+ queueLimit: 100,
+ enableKeepAlive: true,
+ keepAliveInitialDelay: 10000,
})
- this.drizzleDataSource = drizzle({ client: this.drizzleConnection })
}
}
public async destroy(): Promise {
- await Promise.all([this.dataSource?.destroy(), this.drizzleConnection?.end()])
+ await Promise.all([this.dataSource?.destroy(), this.drizzlePool?.end()])
this.dataSource = undefined
- this.drizzleConnection = undefined
- this.drizzleDataSource = undefined
+ this.drizzlePool = undefined
if (this.redisClient) {
await this.redisClient.quit()
this.redisClient = undefined
diff --git a/database/src/queries/openaiThreads.test.ts b/database/src/queries/openaiThreads.test.ts
index f6eb94c6e..31003840d 100644
--- a/database/src/queries/openaiThreads.test.ts
+++ b/database/src/queries/openaiThreads.test.ts
@@ -23,7 +23,7 @@ afterAll(async () => {
describe('openaiThreads query test', () => {
it('should insert a new openai thread', async () => {
- await Promise.resolve([dbInsertOpenaiThread('7', 1), dbInsertOpenaiThread('72', 6)])
+ await Promise.all([dbInsertOpenaiThread('7', 1), dbInsertOpenaiThread('72', 6)])
const result = await db.select().from(openaiThreadsTable)
expect(result).toHaveLength(2)
expect(result).toMatchObject([
diff --git a/database/src/queries/user.ts b/database/src/queries/user.ts
index 9e7d84c27..2a1c474d7 100644
--- a/database/src/queries/user.ts
+++ b/database/src/queries/user.ts
@@ -1,6 +1,6 @@
import { getLogger } from 'log4js'
import { aliasSchema, emailSchema, uuidv4Schema } from 'shared'
-import { Raw } from 'typeorm'
+import { In, Raw } from 'typeorm'
import { User as DbUser, UserContact as DbUserContact } from '../entity'
import { findWithCommunityIdentifier, LOG4JS_QUERIES_CATEGORY_NAME } from './index'
@@ -81,3 +81,15 @@ export async function findForeignUserByUuids(
where: { foreign: true, communityUuid, gradidoID },
})
}
+
+export async function findUserNamesByIds(userIds: number[]): Promise