diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dc91f2fa..d52ba760c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,72 @@ 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). +#### [1.20.0](https://github.com/gradido/gradido/compare/1.19.1...1.20.0) + +- fix(backend): no await for emails [`#2918`](https://github.com/gradido/gradido/pull/2918) +- fix(frontend): no receiver on send by link [`#2933`](https://github.com/gradido/gradido/pull/2933) +- fix(admin): pagination set currentPage by switch tabs [`#2902`](https://github.com/gradido/gradido/pull/2902) +- fix(federation): correct export of the community url [`#2931`](https://github.com/gradido/gradido/pull/2931) +- fix(frontend): displayed decay duration [`#2927`](https://github.com/gradido/gradido/pull/2927) +- fix(frontend): community tab navigation [`#2928`](https://github.com/gradido/gradido/pull/2928) +- fix(frontend): moderator id missing [`#2925`](https://github.com/gradido/gradido/pull/2925) +- fix(frontend): reset button send coins [`#2924`](https://github.com/gradido/gradido/pull/2924) +- refactor(backend): eslint plugin import export style [`#2908`](https://github.com/gradido/gradido/pull/2908) +- fix(backend): vscode intellisense fixes [`#2919`](https://github.com/gradido/gradido/pull/2919) +- refactor(backend): eslint import-no-cycle enabled [`#2905`](https://github.com/gradido/gradido/pull/2905) +- docs(backend): alias rules and conventions [`#2881`](https://github.com/gradido/gradido/pull/2881) +- refactor(backend): get transaction list [`#2923`](https://github.com/gradido/gradido/pull/2923) +- feat(backend): previous balance in transaction [`#2914`](https://github.com/gradido/gradido/pull/2914) +- refactor(backend): eslint update packages [`#2829`](https://github.com/gradido/gradido/pull/2829) +- feat(frontend): send coins via gradido ID [`#2837`](https://github.com/gradido/gradido/pull/2837) +- refactor(database): cleanup database [`#2808`](https://github.com/gradido/gradido/pull/2808) +- refactor(backend): eslint plugin n + fixes [`#2828`](https://github.com/gradido/gradido/pull/2828) +- feat(frontend): add link to download QR-Code [`#2889`](https://github.com/gradido/gradido/pull/2889) +- fix(other): delete node_modules and /tmp/yarn--* on start.sh [`#2904`](https://github.com/gradido/gradido/pull/2904) +- fix(admin): add confirmation modal for user role change and user (un)deletion [`#2880`](https://github.com/gradido/gradido/pull/2880) +- fix(admin): admin open contribution edit button [`#2811`](https://github.com/gradido/gradido/pull/2811) +- fix(backend): import order [`#2911`](https://github.com/gradido/gradido/pull/2911) +- fix(other): use default values for undefined .env database values [`#2910`](https://github.com/gradido/gradido/pull/2910) +- refactor(backend): eslint plugin import + fixes [`#2827`](https://github.com/gradido/gradido/pull/2827) +- refactor(backend): missing event tests [`#2900`](https://github.com/gradido/gradido/pull/2900) +- refactor(backend): unify event names [`#2799`](https://github.com/gradido/gradido/pull/2799) +- feat(backend): events for users [`#2797`](https://github.com/gradido/gradido/pull/2797) +- fix(backend): subscription get's email and languages from user [`#2885`](https://github.com/gradido/gradido/pull/2885) +- refactor(backend): eslint-plugin-jest + fixes [`#2816`](https://github.com/gradido/gradido/pull/2816) +- fix(frontend): fr change ` and ยด to ' [`#2888`](https://github.com/gradido/gradido/pull/2888) +- feat(backend): events for transaction links [`#2792`](https://github.com/gradido/gradido/pull/2792) +- feat(backend): events for contributions [`#2784`](https://github.com/gradido/gradido/pull/2784) +- feat(backend): events for contribution messages [`#2783`](https://github.com/gradido/gradido/pull/2783) +- refactor(backend): upgrade coverage to 85% [`#2884`](https://github.com/gradido/gradido/pull/2884) +- refactor(backend): add klicktipp-api library [`#2883`](https://github.com/gradido/gradido/pull/2883) +- feat(backend): events for contribution links [`#2780`](https://github.com/gradido/gradido/pull/2780) +- refactor(backend): separate events in own files [`#2777`](https://github.com/gradido/gradido/pull/2777) +- refactor(backend): rename `evenProtocolType` to `eventType` [`#2776`](https://github.com/gradido/gradido/pull/2776) +- refactor(other): add yarn installAll on gradido folder [`#2703`](https://github.com/gradido/gradido/pull/2703) +- docs(federation): describe the technical federation architecture [`#2716`](https://github.com/gradido/gradido/pull/2716) +- refactor(admin): admin list contributions for creation transaction list query [`#2791`](https://github.com/gradido/gradido/pull/2791) +- refactor(workflow): separate workflow with file filter for nginx testing [`#2871`](https://github.com/gradido/gradido/pull/2871) +- feat(backend): read communities data from database [`#2807`](https://github.com/gradido/gradido/pull/2807) +- feat(federation): implement a graphql endpoint to answer getpublickey-request [`#2651`](https://github.com/gradido/gradido/pull/2651) +- refactor(workflow): add file filters to dht node and federation workflows [`#2838`](https://github.com/gradido/gradido/pull/2838) +- refactor(workflow): separate test workflow for end-to-end tests [`#2836`](https://github.com/gradido/gradido/pull/2836) +- refactor(workflow): separate test workflow for frontend [`#2835`](https://github.com/gradido/gradido/pull/2835) +- feat(federation): add federation modul to deployment scripts [`#2733`](https://github.com/gradido/gradido/pull/2733) +- refactor(database): event table [`#2720`](https://github.com/gradido/gradido/pull/2720) +- refactor(workflow): separate test workflow with file change filters for admin interface [`#2734`](https://github.com/gradido/gradido/pull/2734) +- fix(admin): fix translation in menu (english) [`#2814`](https://github.com/gradido/gradido/pull/2814) +- refactor(workflow): configure jest to directly check coverage to schlanken the test workflows [`#2790`](https://github.com/gradido/gradido/pull/2790) +- fix(database): removed commands from package.json not working [`#2805`](https://github.com/gradido/gradido/pull/2805) +- fix(other): repair UserProfile.ChangePassword.feature scenario [`#2782`](https://github.com/gradido/gradido/pull/2782) +- feat(backend): test double redeem transaction links [`#2788`](https://github.com/gradido/gradido/pull/2788) +- feat(backend): admin open creations query [`#2813`](https://github.com/gradido/gradido/pull/2813) +- refactor(backend): eslint-plugin-type-graphql + fixes [`#2745`](https://github.com/gradido/gradido/pull/2745) + #### [1.19.1](https://github.com/gradido/gradido/compare/1.19.0...1.19.1) +> 10 March 2023 + +- chore(other): upgrade version to 1.19.1 [`#2812`](https://github.com/gradido/gradido/pull/2812) - fix(frontend): admin question clickable [`#2810`](https://github.com/gradido/gradido/pull/2810) - refactor(frontend): change b-img to b-icon send [`#2809`](https://github.com/gradido/gradido/pull/2809) - fix(admin): update openCreation in case of tab open. [`#2806`](https://github.com/gradido/gradido/pull/2806) diff --git a/admin/package.json b/admin/package.json index 521f34bfc..04c9a60e8 100644 --- a/admin/package.json +++ b/admin/package.json @@ -3,7 +3,7 @@ "description": "Administraion Interface for Gradido", "main": "index.js", "author": "Moriz Wahl", - "version": "1.19.1", + "version": "1.20.0", "license": "Apache-2.0", "private": false, "scripts": { diff --git a/backend/package.json b/backend/package.json index 1457f97e5..c5e0df3c5 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "gradido-backend", - "version": "1.19.1", + "version": "1.20.0", "description": "Gradido unified backend providing an API-Service for Gradido Transactions", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/backend", diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 017d83098..0c36e4d5a 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -76,7 +76,7 @@ const email = { EMAIL_SENDER: process.env.EMAIL_SENDER || 'info@gradido.net', EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || '', EMAIL_SMTP_URL: process.env.EMAIL_SMTP_URL || 'mailserver', - EMAIL_SMTP_PORT: process.env.EMAIL_SMTP_PORT || '1025', + EMAIL_SMTP_PORT: Number(process.env.EMAIL_SMTP_PORT) || 1025, // eslint-disable-next-line no-unneeded-ternary EMAIL_TLS: process.env.EMAIL_TLS === 'false' ? false : true, EMAIL_LINK_VERIFICATION: diff --git a/backend/src/emails/sendEmailTranslated.test.ts b/backend/src/emails/sendEmailTranslated.test.ts index 66efb29a9..0e04db732 100644 --- a/backend/src/emails/sendEmailTranslated.test.ts +++ b/backend/src/emails/sendEmailTranslated.test.ts @@ -10,7 +10,7 @@ import { sendEmailTranslated } from './sendEmailTranslated' CONFIG.EMAIL = false CONFIG.EMAIL_SMTP_URL = 'EMAIL_SMTP_URL' -CONFIG.EMAIL_SMTP_PORT = '1234' +CONFIG.EMAIL_SMTP_PORT = 1234 CONFIG.EMAIL_USERNAME = 'user' CONFIG.EMAIL_PASSWORD = 'pwd' CONFIG.EMAIL_TLS = true @@ -31,7 +31,7 @@ jest.mock('nodemailer', () => { }) describe('sendEmailTranslated', () => { - let result: Record | null + let result: Record | boolean | null describe('config email is false', () => { beforeEach(async () => { diff --git a/backend/src/emails/sendEmailTranslated.ts b/backend/src/emails/sendEmailTranslated.ts index abf582b5c..879d17656 100644 --- a/backend/src/emails/sendEmailTranslated.ts +++ b/backend/src/emails/sendEmailTranslated.ts @@ -1,4 +1,5 @@ -/* eslint-disable @typescript-eslint/restrict-template-expressions */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ import path from 'path' import Email from 'email-templates' @@ -6,44 +7,46 @@ import i18n from 'i18n' import { createTransport } from 'nodemailer' import { CONFIG } from '@/config' -import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' -export const sendEmailTranslated = async (params: { +export const sendEmailTranslated = async ({ + receiver, + template, + locals, +}: { receiver: { to: string cc?: string } template: string locals: Record -}): Promise | null> => { - let resultSend: Record | null = null - +}): Promise | boolean | null> => { // TODO: test the calling order of 'i18n.setLocale' for example: language of logging 'en', language of email receiver 'es', reset language of current user 'de' - // because language of receiver can differ from language of current user who triggers the sending - const rememberLocaleToRestore = i18n.getLocale() - - i18n.setLocale('en') // for logging - logger.info( - `send Email: language=${params.locals.locale} to=${params.receiver.to}` + - (params.receiver.cc ? `, cc=${params.receiver.cc}` : '') + - `, subject=${i18n.__('emails.' + params.template + '.subject')}`, - ) - if (!CONFIG.EMAIL) { logger.info(`Emails are disabled via config...`) return null } + + // because language of receiver can differ from language of current user who triggers the sending + // const rememberLocaleToRestore = i18n.getLocale() + + i18n.setLocale('en') // for logging + logger.info( + `send Email: language=${locals.locale as string} to=${receiver.to}` + + (receiver.cc ? `, cc=${receiver.cc}` : '') + + `, subject=${i18n.__('emails.' + template + '.subject')}`, + ) + if (CONFIG.EMAIL_TEST_MODUS) { logger.info( - `Testmodus=ON: change receiver from ${params.receiver.to} to ${CONFIG.EMAIL_TEST_RECEIVER}`, + `Testmodus=ON: change receiver from ${receiver.to} to ${CONFIG.EMAIL_TEST_RECEIVER}`, ) - params.receiver.to = CONFIG.EMAIL_TEST_RECEIVER + receiver.to = CONFIG.EMAIL_TEST_RECEIVER } const transport = createTransport({ host: CONFIG.EMAIL_SMTP_URL, - port: Number(CONFIG.EMAIL_SMTP_PORT), + port: CONFIG.EMAIL_SMTP_PORT, secure: false, // true for 465, false for other ports requireTLS: CONFIG.EMAIL_TLS, auth: { @@ -52,7 +55,7 @@ export const sendEmailTranslated = async (params: { }, }) - i18n.setLocale(params.locals.locale as string) // for email + i18n.setLocale(locals.locale as string) // for email // TESTING: see 'README.md' const email = new Email({ @@ -64,23 +67,16 @@ export const sendEmailTranslated = async (params: { // i18n, // is only needed if you don't install i18n }) - // ATTENTION: await is needed, because otherwise on send the email gets send in the language of the current user, because below the language gets reset - await email + const resultSend = await email .send({ - template: path.join(__dirname, 'templates', params.template), - message: params.receiver, - locals: params.locals, // the 'locale' in here seems not to be used by 'email-template', because it doesn't work if the language isn't set before by 'i18n.setLocale' - }) - .then((result: Record) => { - resultSend = result - logger.info('Send email successfully !!!') - logger.info('Result: ', result) + template: path.join(__dirname, 'templates', template), + message: receiver, + locals, // the 'locale' in here seems not to be used by 'email-template', because it doesn't work if the language isn't set before by 'i18n.setLocale' }) .catch((error: unknown) => { - throw new LogError('Error sending notification email', error) + logger.error('Error sending notification email', error) + return false }) - i18n.setLocale(rememberLocaleToRestore) - return resultSend } diff --git a/backend/src/emails/sendEmailVariants.ts b/backend/src/emails/sendEmailVariants.ts index 2f9d906a1..ff7709380 100644 --- a/backend/src/emails/sendEmailVariants.ts +++ b/backend/src/emails/sendEmailVariants.ts @@ -13,7 +13,7 @@ export const sendAddedContributionMessageEmail = (data: { senderFirstName: string senderLastName: string contributionMemo: string -}): Promise | null> => { +}): Promise | boolean | null> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>`, @@ -40,7 +40,7 @@ export const sendAccountActivationEmail = (data: { language: string activationLink: string timeDurationObject: Record -}): Promise | null> => { +}): Promise | boolean | null> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'accountActivation', @@ -62,7 +62,7 @@ export const sendAccountMultiRegistrationEmail = (data: { lastName: string email: string language: string -}): Promise | null> => { +}): Promise | boolean | null> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'accountMultiRegistration', @@ -86,7 +86,7 @@ export const sendContributionConfirmedEmail = (data: { senderLastName: string contributionMemo: string contributionAmount: Decimal -}): Promise | null> => { +}): Promise | boolean | null> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'contributionConfirmed', @@ -113,7 +113,7 @@ export const sendContributionDeletedEmail = (data: { senderFirstName: string senderLastName: string contributionMemo: string -}): Promise | null> => { +}): Promise | boolean | null> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'contributionDeleted', @@ -139,7 +139,7 @@ export const sendContributionDeniedEmail = (data: { senderFirstName: string senderLastName: string contributionMemo: string -}): Promise | null> => { +}): Promise | boolean | null> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'contributionDenied', @@ -164,7 +164,7 @@ export const sendResetPasswordEmail = (data: { language: string resetLink: string timeDurationObject: Record -}): Promise | null> => { +}): Promise | boolean | null> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'resetPassword', @@ -191,7 +191,7 @@ export const sendTransactionLinkRedeemedEmail = (data: { senderEmail: string transactionMemo: string transactionAmount: Decimal -}): Promise | null> => { +}): Promise | boolean | null> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'transactionLinkRedeemed', @@ -220,7 +220,7 @@ export const sendTransactionReceivedEmail = (data: { senderLastName: string senderEmail: string transactionAmount: Decimal -}): Promise | null> => { +}): Promise | boolean | null> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'transactionReceived', diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index 236132f4d..b7fd37787 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -146,7 +146,7 @@ export class ContributionMessageResolver { await queryRunner.manager.update(DbContribution, { id: contributionId }, contribution) } - await sendAddedContributionMessageEmail({ + void sendAddedContributionMessageEmail({ firstName: contribution.user.firstName, lastName: contribution.user.lastName, email: contribution.user.emailContact.email, diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 839709f5d..bda108638 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -149,7 +149,7 @@ export const executeTransaction = async ( } finally { await queryRunner.release() } - await sendTransactionReceivedEmail({ + void sendTransactionReceivedEmail({ firstName: recipient.firstName, lastName: recipient.lastName, email: recipient.emailContact.email, @@ -160,7 +160,7 @@ export const executeTransaction = async ( transactionAmount: amount, }) if (transactionLink) { - await sendTransactionLinkRedeemedEmail({ + void sendTransactionLinkRedeemedEmail({ firstName: sender.firstName, lastName: sender.lastName, email: sender.emailContact.email, diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 35e00a5ec..60b4403af 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -245,7 +245,7 @@ export class UserResolver { user.publisherId = publisherId logger.debug('partly faked user', user) - const emailSent = await sendAccountMultiRegistrationEmail({ + void sendAccountMultiRegistrationEmail({ firstName: foundUser.firstName, // this is the real name of the email owner, but just "firstName" would be the name of the new registrant which shall not be passed to the outside lastName: foundUser.lastName, // this is the real name of the email owner, but just "lastName" would be the name of the new registrant which shall not be passed to the outside email, @@ -258,9 +258,6 @@ export class UserResolver { ) /* uncomment this, when you need the activation link on the console */ // In case EMails are disabled log the activation link for the user - if (!emailSent) { - logger.debug(`Email not send!`) - } logger.info('createUser() faked and send multi registration mail...') return user @@ -325,8 +322,7 @@ export class UserResolver { emailContact.emailVerificationCode.toString(), ).replace(/{code}/g, redeemCode ? '/' + redeemCode : '') - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const emailSent = await sendAccountActivationEmail({ + void sendAccountActivationEmail({ firstName, lastName, email, @@ -338,10 +334,6 @@ export class UserResolver { await EVENT_EMAIL_CONFIRMATION(dbUser) - if (!emailSent) { - logger.debug(`Account confirmation link: ${activationLink}`) - } - await queryRunner.commitTransaction() logger.addContext('user', dbUser.id) } catch (e) { @@ -392,8 +384,8 @@ export class UserResolver { }) logger.info(`optInCode for ${email}=${user.emailContact}`) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const emailSent = await sendResetPasswordEmail({ + + void sendResetPasswordEmail({ firstName: user.firstName, lastName: user.lastName, email, @@ -402,13 +394,6 @@ export class UserResolver { timeDurationObject: getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME), }) - /* uncomment this, when you need the activation link on the console */ - // In case EMails are disabled log the activation link for the user - if (!emailSent) { - logger.debug( - `Reset password link: ${activationLink(user.emailContact.emailVerificationCode)}`, - ) - } logger.info(`forgotPassword(${email}) successful...`) await EVENT_EMAIL_FORGOT_PASSWORD(user) @@ -804,7 +789,7 @@ export class UserResolver { await user.emailContact.save() // eslint-disable-next-line @typescript-eslint/no-unused-vars - const emailSent = await sendAccountActivationEmail({ + void sendAccountActivationEmail({ firstName: user.firstName, lastName: user.lastName, email, @@ -813,10 +798,6 @@ export class UserResolver { timeDurationObject: getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME), }) - // In case EMails are disabled log the activation link for the user - if (!emailSent) { - logger.info(`Account confirmation link: ${activationLink}`) - } await EVENT_EMAIL_ADMIN_CONFIRMATION(user, getUser(context)) return true diff --git a/database/package.json b/database/package.json index 6dc8acf8c..23e358364 100644 --- a/database/package.json +++ b/database/package.json @@ -1,6 +1,6 @@ { "name": "gradido-database", - "version": "1.19.1", + "version": "1.20.0", "description": "Gradido Database Tool to execute database migrations", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/database", diff --git a/dht-node/package.json b/dht-node/package.json index 15426e606..1f8ba4505 100644 --- a/dht-node/package.json +++ b/dht-node/package.json @@ -1,6 +1,6 @@ { "name": "gradido-dht-node", - "version": "1.0.0", + "version": "1.20.0", "description": "Gradido dht-node module", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/", diff --git a/federation/package.json b/federation/package.json index e7e067435..3173e77ab 100644 --- a/federation/package.json +++ b/federation/package.json @@ -1,6 +1,6 @@ { "name": "gradido-federation", - "version": "1.0.0", + "version": "1.20.0", "description": "Gradido federation module providing Gradido-Hub-Federation and versioned API for inter community communication", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/federation", @@ -45,14 +45,16 @@ "eslint-plugin-prettier": "^3.4.0", "eslint-plugin-promise": "^5.1.0", "jest": "27.2.4", + "nodemon": "^2.0.7", + "prettier": "^2.3.1", "ts-jest": "27.0.5", "ts-node": "^10.9.1", "tsconfig-paths": "^4.1.1", - "nodemon": "^2.0.7", - "prettier": "^2.3.1", "typescript": "^4.3.4" }, "nodemonConfig": { - "ignore": ["**/*.test.ts"] + "ignore": [ + "**/*.test.ts" + ] } } diff --git a/frontend/package.json b/frontend/package.json index 812735e3e..8515ca209 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "bootstrap-vue-gradido-wallet", - "version": "1.19.1", + "version": "1.20.0", "private": true, "scripts": { "start": "node run/server.js", diff --git a/package.json b/package.json index c91c63532..7845d722b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gradido", - "version": "1.19.1", + "version": "1.20.0", "description": "Gradido", "main": "index.js", "repository": "git@github.com:gradido/gradido.git",