Merge remote-tracking branch 'origin/master' into
3573-feature-introduce-distributed-semaphore-base-on-redis
17
.github/workflows/test_backend.yml
vendored
@ -92,19 +92,4 @@ jobs:
|
||||
bun install --global --no-save turbo@^2
|
||||
|
||||
- name: Backend | Typecheck
|
||||
run: turbo backend#typecheck backend#build
|
||||
|
||||
locales:
|
||||
if: needs.files-changed.outputs.backend == 'true'
|
||||
name: Locales - Backend
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: install bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Backend | Locales
|
||||
run: cd backend && bun locales
|
||||
run: turbo backend#typecheck backend#build
|
||||
15
.github/workflows/test_core.yml
vendored
@ -43,3 +43,18 @@ jobs:
|
||||
- name: typecheck && unit test
|
||||
run: turbo core#test core#typecheck
|
||||
|
||||
locales:
|
||||
if: needs.files-changed.outputs.core == 'true'
|
||||
name: Locales - Core
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: install bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Core | Locales
|
||||
run: cd core && bun locales
|
||||
|
||||
|
||||
13
CHANGELOG.md
@ -4,9 +4,18 @@ 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.0](https://github.com/gradido/gradido/compare/v2.7.0...v2.7.0)
|
||||
#### [v2.7.1](https://github.com/gradido/gradido/compare/v2.7.0...v2.7.1)
|
||||
|
||||
- fixes [`414ff8a`](https://github.com/gradido/gradido/commit/414ff8ac5a7477109f80123ccca5c4c8ed4511b2)
|
||||
- feat(frontend): new startpage images [`#3576`](https://github.com/gradido/gradido/pull/3576)
|
||||
- feat(frontend): update login subtitle [`#3574`](https://github.com/gradido/gradido/pull/3574)
|
||||
- feat(frontend): update copy symbol and change link order [`#3575`](https://github.com/gradido/gradido/pull/3575)
|
||||
- fix(backend): correct seeding [`#3572`](https://github.com/gradido/gradido/pull/3572)
|
||||
- feat(dlt): dlt-connector takes care of gradido node [`#3568`](https://github.com/gradido/gradido/pull/3568)
|
||||
- refactor(dlt): upgrade dlt for using gradido blockchain lib and hiero [`#3551`](https://github.com/gradido/gradido/pull/3551)
|
||||
- chore(release): v2.7.0 [`#3557`](https://github.com/gradido/gradido/pull/3557)
|
||||
- feat(federation): use own table for handshake state [`#3555`](https://github.com/gradido/gradido/pull/3555)
|
||||
- fix(workflow): use bun instead of yarn [`#3550`](https://github.com/gradido/gradido/pull/3550)
|
||||
- feat(workflow): adjust for new bun version [`#3554`](https://github.com/gradido/gradido/pull/3554)
|
||||
|
||||
#### [v2.7.0](https://github.com/gradido/gradido/compare/2.6.1...v2.7.0)
|
||||
|
||||
|
||||
@ -189,11 +189,11 @@ describe('test', () => {
|
||||
```ts
|
||||
import { clearLogs, printLogs } from 'config-schema/test/testSetup'
|
||||
```
|
||||
- vitest (frontend, admin, database):
|
||||
- vitest (frontend, admin):
|
||||
```ts
|
||||
import { clearLogs, printLogs } from 'config-schema/test/testSetup.vitest'
|
||||
```
|
||||
- bun (shared, core):
|
||||
- bun (shared, core, database):
|
||||
```ts
|
||||
import { clearLogs, printLogs } from 'config-schema/test/testSetup.bun'
|
||||
```
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"description": "Administration Interface for Gradido",
|
||||
"main": "index.js",
|
||||
"author": "Gradido Academy - https://www.gradido.net",
|
||||
"version": "2.7.0",
|
||||
"version": "2.7.1",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@ -1,77 +0,0 @@
|
||||
# Server
|
||||
PORT=4000
|
||||
JWT_SECRET=secret123
|
||||
JWT_EXPIRES_IN=10m
|
||||
GRAPHIQL=false
|
||||
GDT_API_URL=https://gdt.gradido.net
|
||||
|
||||
# Database
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_USER=root
|
||||
DB_PASSWORD=
|
||||
DB_DATABASE=gradido_community
|
||||
TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log
|
||||
|
||||
# Klicktipp
|
||||
KLICKTIPP=false
|
||||
KLICKTTIPP_API_URL=https://api.klicktipp.com
|
||||
KLICKTIPP_USER=gradido_test
|
||||
KLICKTIPP_PASSWORD=secret321
|
||||
KLICKTIPP_APIKEY_DE=SomeFakeKeyDE
|
||||
KLICKTIPP_APIKEY_EN=SomeFakeKeyEN
|
||||
|
||||
# DltConnector
|
||||
DLT_CONNECTOR=true
|
||||
DLT_CONNECTOR_URL=http://localhost:6010
|
||||
|
||||
# Community
|
||||
COMMUNITY_NAME=Gradido Entwicklung
|
||||
COMMUNITY_URL=http://localhost
|
||||
COMMUNITY_REGISTER_PATH=/register
|
||||
COMMUNITY_REDEEM_PATH=/redeem/{code}
|
||||
COMMUNITY_REDEEM_CONTRIBUTION_PATH=/redeem/CL-{code}
|
||||
COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido.
|
||||
COMMUNITY_SUPPORT_MAIL=support@supportmail.com
|
||||
|
||||
# Login Server
|
||||
LOGIN_APP_SECRET=21ffbbc616fe
|
||||
LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a
|
||||
|
||||
# EMail
|
||||
EMAIL=false
|
||||
EMAIL_TEST_MODUS=false
|
||||
EMAIL_TEST_RECEIVER=stage1@gradido.net
|
||||
EMAIL_USERNAME=gradido_email
|
||||
EMAIL_SENDER=info@gradido.net
|
||||
EMAIL_PASSWORD=xxx
|
||||
EMAIL_SMTP_HOST=gmail.com
|
||||
EMAIL_SMTP_PORT=587
|
||||
EMAIL_LINK_VERIFICATION_PATH=/checkEmail/{optin}{code}
|
||||
EMAIL_LINK_SETPASSWORD_PATH=/reset-password/{optin}
|
||||
EMAIL_LINK_FORGOTPASSWORD_PATH=/forgot-password
|
||||
EMAIL_LINK_OVERVIEW_PATH=/overview
|
||||
EMAIL_CODE_VALID_TIME=1440
|
||||
EMAIL_CODE_REQUEST_TIME=10
|
||||
|
||||
# Webhook
|
||||
WEBHOOK_ELOPAGE_SECRET=secret
|
||||
|
||||
# SET LOG LEVEL AS NEEDED IN YOUR .ENV
|
||||
# POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal
|
||||
LOG_LEVEL=INFO
|
||||
|
||||
# Federation
|
||||
FEDERATION_VALIDATE_COMMUNITY_TIMER=60000
|
||||
|
||||
# GMS
|
||||
# GMS_ACTIVE=true
|
||||
# Coordinates of Illuminz test instance
|
||||
#GMS_API_URL=http://54.176.169.179:3071
|
||||
GMS_API_URL=http://localhost:4044
|
||||
GMS_DASHBOARD_URL=http://localhost:8080
|
||||
|
||||
# HUMHUB
|
||||
HUMHUB_ACTIVE=true
|
||||
HUMHUB_API_URL=https://community-test.gradido.net
|
||||
HUMHUB_JWT_KEY=GwdkIKi-rkRS0mXC4Cg3MYc3ktZh89VFmntDpNKET_dUfcIdjL_957F3nCv3brNtDfbbV81NViKaktUsfExrkH
|
||||
@ -114,8 +114,7 @@ COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/backend/build/worker.js ./wo
|
||||
# add node_modules from production_node_modules
|
||||
COPY --chown=app:app --from=production-node-modules ${DOCKER_WORKDIR}/node_modules ./node_modules
|
||||
|
||||
# Copy locales
|
||||
COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/backend/locales ./locales
|
||||
COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/core/build/templates ./templates
|
||||
|
||||
# Run command
|
||||
CMD ["node", "index.js"]
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "backend",
|
||||
"version": "2.7.0",
|
||||
"version": "2.7.1",
|
||||
"private": false,
|
||||
"description": "Gradido unified backend providing an API-Service for Gradido Transactions",
|
||||
"repository": "https://github.com/gradido/gradido/backend",
|
||||
@ -8,7 +8,7 @@
|
||||
"author": "Gradido Academy - https://www.gradido.net",
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "ts-node ./esbuild.config.ts && mkdirp build/templates/ && ncp src/emails/templates build/templates && mkdirp locales/ && ncp src/locales locales",
|
||||
"build": "ts-node ./esbuild.config.ts && mkdirp build/templates/ && ncp ../core/build/templates build/templates",
|
||||
"dev": "cross-env TZ=UTC nodemon -w src --ext ts,pug,json,css -r tsconfig-paths/register src/index.ts",
|
||||
"test": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_backend jest --runInBand --forceExit --detectOpenHandles",
|
||||
"test:coverage": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_backend jest --coverage --runInBand --forceExit --detectOpenHandles",
|
||||
@ -19,8 +19,6 @@
|
||||
"lint": "biome check --error-on-warnings .",
|
||||
"lint:fix": "biome check --error-on-warnings . --write",
|
||||
"lint:fix:unsafe": "biome check --fix --unsafe",
|
||||
"locales": "scripts/sort.sh",
|
||||
"locales:fix": "scripts/sort.sh --fix",
|
||||
"start": "cross-env TZ=UTC node build/index.js",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo"
|
||||
@ -50,7 +48,6 @@
|
||||
"@types/jest": "27.0.2",
|
||||
"@types/lodash.clonedeep": "^4.5.6",
|
||||
"@types/node": "^17.0.21",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"@types/sodium-native": "^2.3.5",
|
||||
"@types/source-map-support": "^0.5.10",
|
||||
"@types/uuid": "^8.3.4",
|
||||
@ -84,11 +81,9 @@
|
||||
"log4js": "^6.7.1",
|
||||
"mkdirp": "^3.0.1",
|
||||
"ncp": "^2.0.0",
|
||||
"nodemailer": "^6.6.5",
|
||||
"nodemon": "^2.0.7",
|
||||
"openai": "^4.87.3",
|
||||
"prettier": "^3.5.3",
|
||||
"pug": "^3.0.2",
|
||||
"random-bigint": "^0.0.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
def walk(f):
|
||||
. as $in
|
||||
| if type == "object" then
|
||||
reduce keys_unsorted[] as $key
|
||||
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
|
||||
elif type == "array" then map( walk(f) ) | f
|
||||
else f
|
||||
end;
|
||||
|
||||
def keys_sort_by(f):
|
||||
to_entries | sort_by(.key|f ) | from_entries;
|
||||
|
||||
walk(if type == "object" then keys_sort_by(ascii_upcase) else . end)
|
||||
@ -4,7 +4,7 @@ import { User as DbUser } from 'database'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
// import { createGmsUser } from '@/apis/gms/GmsClient'
|
||||
// import { GmsUser } from '@/apis/gms/model/GmsUser'
|
||||
import { CONFIG } from '@/config'
|
||||
import { CONFIG as CORE_CONFIG } from 'core'
|
||||
import { sendUserToGms } from '@/graphql/resolver/util/sendUserToGms'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { initLogging } from '@/server/logger'
|
||||
@ -13,7 +13,7 @@ import { getLogger } from 'log4js'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.gms.ExportUsers`)
|
||||
|
||||
CONFIG.EMAIL = false
|
||||
CORE_CONFIG.EMAIL = false
|
||||
// use force to copy over all user even if gmsRegistered is set to true
|
||||
const forceMode = process.argv.includes('--force')
|
||||
|
||||
|
||||
@ -92,6 +92,7 @@ export class OpenaiClient {
|
||||
if (openaiThreadEntity.updatedAt < new Date(Date.now() - OPENAI_AI_THREAD_DEFAULT_TIMEOUT_DAYS * 24 * 60 * 60 * 1000)) {
|
||||
logger.info(`Openai thread for user: ${user.id} is older than ${OPENAI_AI_THREAD_DEFAULT_TIMEOUT_DAYS} days, deleting...`)
|
||||
// let run async, because it could need some time, but we don't need to wait, because we create a new one nevertheless
|
||||
// biome-ignore lint/complexity/noVoid: start it intentionally async without waiting for result
|
||||
void this.deleteThread(openaiThreadEntity.id)
|
||||
return []
|
||||
}
|
||||
|
||||
@ -64,22 +64,10 @@ const loginServer = {
|
||||
}
|
||||
|
||||
const email = {
|
||||
EMAIL: process.env.EMAIL === 'true',
|
||||
EMAIL_TEST_MODUS: process.env.EMAIL_TEST_MODUS === 'true',
|
||||
EMAIL_TEST_RECEIVER: process.env.EMAIL_TEST_RECEIVER ?? 'stage1@gradido.net',
|
||||
EMAIL_USERNAME: process.env.EMAIL_USERNAME ?? '',
|
||||
EMAIL_SENDER: process.env.EMAIL_SENDER ?? 'info@gradido.net',
|
||||
EMAIL_PASSWORD: process.env.EMAIL_PASSWORD ?? '',
|
||||
EMAIL_SMTP_HOST: process.env.EMAIL_SMTP_HOST ?? 'mailserver',
|
||||
EMAIL_SMTP_PORT: Number(process.env.EMAIL_SMTP_PORT) || 1025,
|
||||
|
||||
EMAIL_TLS: process.env.EMAIL_TLS !== 'false',
|
||||
EMAIL_LINK_VERIFICATION:
|
||||
COMMUNITY_URL + (process.env.EMAIL_LINK_VERIFICATION_PATH ?? '/checkEmail/'),
|
||||
EMAIL_LINK_SETPASSWORD:
|
||||
COMMUNITY_URL + (process.env.EMAIL_LINK_SETPASSWORD_PATH ?? '/reset-password/'),
|
||||
EMAIL_LINK_FORGOTPASSWORD:
|
||||
COMMUNITY_URL + (process.env.EMAIL_LINK_FORGOTPASSWORD_PATH ?? '/forgot-password'),
|
||||
EMAIL_LINK_OVERVIEW: COMMUNITY_URL + (process.env.EMAIL_LINK_OVERVIEW_PATH ?? '/overview'),
|
||||
// time in minutes a optin code is valid
|
||||
EMAIL_CODE_VALID_TIME: process.env.EMAIL_CODE_VALID_TIME
|
||||
|
||||
@ -83,76 +83,6 @@ export const schema = Joi.object({
|
||||
.default('~/.gradido')
|
||||
.description('The home folder for the gradido dlt node server'),
|
||||
|
||||
EMAIL: Joi.boolean()
|
||||
.default(false)
|
||||
.description('Enable or disable email functionality')
|
||||
.required(),
|
||||
|
||||
EMAIL_TEST_MODUS: Joi.boolean()
|
||||
.default(false)
|
||||
.description('When enabled, all emails are sended to EMAIL_TEST_RECEIVER')
|
||||
.optional(),
|
||||
|
||||
EMAIL_TEST_RECEIVER: Joi.string()
|
||||
.email()
|
||||
.default('stage1@gradido.net')
|
||||
.when('EMAIL_TEST_MODUS', { is: true, then: Joi.required() })
|
||||
.description('Email address used in test mode'),
|
||||
|
||||
EMAIL_USERNAME: Joi.alternatives().conditional(Joi.ref('EMAIL'), {
|
||||
is: true,
|
||||
then: Joi.alternatives().conditional(Joi.ref('NODE_ENV'), {
|
||||
is: 'development',
|
||||
then: Joi.string()
|
||||
.allow('')
|
||||
.description('Username for SMTP authentication (optional in development)'),
|
||||
otherwise: Joi.string()
|
||||
.pattern(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)
|
||||
.description('Valid SMTP username required in production')
|
||||
.required(),
|
||||
}),
|
||||
otherwise: Joi.string().allow('').optional(),
|
||||
}),
|
||||
|
||||
EMAIL_SENDER: Joi.string()
|
||||
.email()
|
||||
.when('EMAIL', { is: true, then: Joi.required() })
|
||||
.default('info@gradido.net')
|
||||
.description('Email address used as sender'),
|
||||
|
||||
EMAIL_PASSWORD: Joi.alternatives().conditional(Joi.ref('EMAIL'), {
|
||||
is: true,
|
||||
then: Joi.alternatives().conditional(Joi.ref('NODE_ENV'), {
|
||||
is: 'development',
|
||||
then: Joi.string()
|
||||
.allow('')
|
||||
.description('Password for SMTP authentication (optional in development)'),
|
||||
otherwise: Joi.string()
|
||||
.min(8)
|
||||
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&#]).{8,}$/)
|
||||
.description(
|
||||
'Password must be at least 8 characters long, include uppercase and lowercase letters, a number, and a special character',
|
||||
)
|
||||
.required(),
|
||||
}),
|
||||
otherwise: Joi.string().allow('').optional(),
|
||||
}),
|
||||
|
||||
EMAIL_SMTP_HOST: Joi.string()
|
||||
.hostname()
|
||||
.when('EMAIL', { is: true, then: Joi.required() })
|
||||
.default('mailserver')
|
||||
.description('SMTP server hostname'),
|
||||
|
||||
EMAIL_SMTP_PORT: Joi.number()
|
||||
.integer()
|
||||
.positive()
|
||||
.when('EMAIL', { is: true, then: Joi.required() })
|
||||
.default(1025)
|
||||
.description('SMTP server port'),
|
||||
|
||||
EMAIL_TLS: Joi.boolean().default(true).description('Enable or disable TLS for SMTP').optional(),
|
||||
|
||||
EMAIL_LINK_VERIFICATION: Joi.string()
|
||||
.uri({ scheme: ['http', 'https'] })
|
||||
.custom((value: string, helpers: Joi.CustomHelpers<string>): string | Joi.ErrorReport => {
|
||||
@ -175,17 +105,6 @@ export const schema = Joi.object({
|
||||
.description('Email Verification link for set initial Password.')
|
||||
.required(),
|
||||
|
||||
EMAIL_LINK_FORGOTPASSWORD: Joi.string()
|
||||
.uri({ scheme: ['http', 'https'] })
|
||||
.custom((value: string, helpers: Joi.CustomHelpers<string>): string | Joi.ErrorReport => {
|
||||
if (!value.startsWith(helpers.state.ancestors[0].COMMUNITY_URL)) {
|
||||
return helpers.error('string.pattern.base', { value, communityUrl: COMMUNITY_URL })
|
||||
}
|
||||
return value
|
||||
})
|
||||
.description('Email Verification link for set new Password, when old Password was forgotten.')
|
||||
.required(),
|
||||
|
||||
EMAIL_LINK_OVERVIEW: Joi.string()
|
||||
.uri({ scheme: ['http', 'https'] })
|
||||
.custom((value: string, helpers: Joi.CustomHelpers<string>): string | Joi.ErrorReport => {
|
||||
@ -213,7 +132,7 @@ export const schema = Joi.object({
|
||||
.description('Time in minutes before a new code can be requested')
|
||||
.required(),
|
||||
|
||||
FEDERATION_VALIDATE_COMMUNITY_TIMER: Joi.number()
|
||||
FEDERATION_VALIDATE_COMMUNITY_TIMER: Joi.number()
|
||||
.integer()
|
||||
.min(1000)
|
||||
.default(60000)
|
||||
|
||||
@ -1,225 +0,0 @@
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
import { decimalSeparatorByLanguage } from 'core'
|
||||
|
||||
import { sendEmailTranslated } from './sendEmailTranslated'
|
||||
|
||||
export interface ContributionEmailCommonData {
|
||||
firstName: string
|
||||
lastName: string
|
||||
email: string
|
||||
language: string
|
||||
senderFirstName: string
|
||||
senderLastName: string
|
||||
contributionMemo: string
|
||||
contributionFrontendLink: string
|
||||
}
|
||||
|
||||
function toContributionEmailLocales(data: ContributionEmailCommonData): Record<string, unknown> {
|
||||
return {
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
locale: data.language,
|
||||
senderFirstName: data.senderFirstName,
|
||||
senderLastName: data.senderLastName,
|
||||
contributionMemo: data.contributionMemo,
|
||||
contributionFrontendLink: data.contributionFrontendLink,
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
}
|
||||
}
|
||||
|
||||
export const sendAddedContributionMessageEmail = (
|
||||
data: ContributionEmailCommonData & {
|
||||
message: string
|
||||
},
|
||||
): Promise<Record<string, unknown> | boolean | null> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: {
|
||||
to: `${data.firstName} ${data.lastName} <${data.email}>`,
|
||||
},
|
||||
template: 'addedContributionMessage',
|
||||
locals: {
|
||||
...toContributionEmailLocales(data),
|
||||
message: data.message,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendAccountActivationEmail = (data: {
|
||||
firstName: string
|
||||
lastName: string
|
||||
email: string
|
||||
language: string
|
||||
activationLink: string
|
||||
timeDurationObject: Record<string, unknown>
|
||||
logoUrl?: string | null
|
||||
}): Promise<Record<string, unknown> | boolean | null> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'accountActivation',
|
||||
locals: {
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
locale: data.language,
|
||||
activationLink: data.activationLink,
|
||||
timeDurationObject: data.timeDurationObject,
|
||||
logoUrl: data.logoUrl,
|
||||
resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD,
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
communityURL: CONFIG.COMMUNITY_URL,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendAccountMultiRegistrationEmail = (data: {
|
||||
firstName: string
|
||||
lastName: string
|
||||
email: string
|
||||
language: string
|
||||
}): Promise<Record<string, unknown> | boolean | null> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'accountMultiRegistration',
|
||||
locals: {
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
locale: data.language,
|
||||
resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD,
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
communityURL: CONFIG.COMMUNITY_URL,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendContributionConfirmedEmail = (
|
||||
data: ContributionEmailCommonData & {
|
||||
contributionAmount: Decimal
|
||||
},
|
||||
): Promise<Record<string, unknown> | boolean | null> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'contributionConfirmed',
|
||||
locals: {
|
||||
...toContributionEmailLocales(data),
|
||||
contributionAmount: decimalSeparatorByLanguage(data.contributionAmount, data.language),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendContributionChangedByModeratorEmail = (
|
||||
data: ContributionEmailCommonData & {
|
||||
contributionMemoUpdated: string
|
||||
},
|
||||
): Promise<Record<string, unknown> | boolean | null> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'contributionChangedByModerator',
|
||||
locals: {
|
||||
...toContributionEmailLocales(data),
|
||||
contributionMemoUpdated: data.contributionMemoUpdated,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendContributionDeletedEmail = (
|
||||
data: ContributionEmailCommonData,
|
||||
): Promise<Record<string, unknown> | boolean | null> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'contributionDeleted',
|
||||
locals: toContributionEmailLocales(data),
|
||||
})
|
||||
}
|
||||
|
||||
export const sendContributionDeniedEmail = (
|
||||
data: ContributionEmailCommonData,
|
||||
): Promise<Record<string, unknown> | boolean | null> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'contributionDenied',
|
||||
locals: toContributionEmailLocales(data),
|
||||
})
|
||||
}
|
||||
|
||||
export const sendResetPasswordEmail = (data: {
|
||||
firstName: string
|
||||
lastName: string
|
||||
email: string
|
||||
language: string
|
||||
resetLink: string
|
||||
timeDurationObject: Record<string, unknown>
|
||||
}): Promise<Record<string, unknown> | boolean | null> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'resetPassword',
|
||||
locals: {
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
locale: data.language,
|
||||
resetLink: data.resetLink,
|
||||
timeDurationObject: data.timeDurationObject,
|
||||
resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD,
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
communityURL: CONFIG.COMMUNITY_URL,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendTransactionLinkRedeemedEmail = (data: {
|
||||
firstName: string
|
||||
lastName: string
|
||||
email: string
|
||||
language: string
|
||||
senderFirstName: string
|
||||
senderLastName: string
|
||||
senderEmail: string
|
||||
transactionMemo: string
|
||||
transactionAmount: Decimal
|
||||
}): Promise<Record<string, unknown> | boolean | null> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'transactionLinkRedeemed',
|
||||
locals: {
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
locale: data.language,
|
||||
senderFirstName: data.senderFirstName,
|
||||
senderLastName: data.senderLastName,
|
||||
senderEmail: data.senderEmail,
|
||||
transactionMemo: data.transactionMemo,
|
||||
transactionAmount: decimalSeparatorByLanguage(data.transactionAmount, data.language),
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
communityURL: CONFIG.COMMUNITY_URL,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendTransactionReceivedEmail = (data: {
|
||||
firstName: string
|
||||
lastName: string
|
||||
email: string
|
||||
language: string
|
||||
senderFirstName: string
|
||||
senderLastName: string
|
||||
senderEmail: string
|
||||
memo: string
|
||||
transactionAmount: Decimal
|
||||
}): Promise<Record<string, unknown> | boolean | null> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'transactionReceived',
|
||||
locals: {
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
locale: data.language,
|
||||
memo: data.memo,
|
||||
senderFirstName: data.senderFirstName,
|
||||
senderLastName: data.senderLastName,
|
||||
senderEmail: data.senderEmail,
|
||||
transactionAmount: decimalSeparatorByLanguage(data.transactionAmount, data.language),
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
communityURL: CONFIG.COMMUNITY_URL,
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -5,7 +5,6 @@ import { DataSource } from 'typeorm'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { cleanDB, testEnvironment } from '@test/helpers'
|
||||
import { i18n as localization } from '@test/testSetup'
|
||||
|
||||
import { userFactory } from '@/seeds/factory/user'
|
||||
import { login, updateHomeCommunityQuery } from '@/seeds/graphql/mutations'
|
||||
@ -45,7 +44,7 @@ const peterLoginData = {
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await testEnvironment(getLogger('apollo'), localization)
|
||||
testEnv = await testEnvironment(getLogger('apollo'))
|
||||
mutate = testEnv.mutate
|
||||
query = testEnv.query
|
||||
con = testEnv.con
|
||||
|
||||
@ -5,10 +5,9 @@ import { DataSource } from 'typeorm'
|
||||
|
||||
import { ContributionStatus } from '@enum/ContributionStatus'
|
||||
import { cleanDB, resetToken, testEnvironment } from '@test/helpers'
|
||||
import { i18n as localization } from '@test/testSetup'
|
||||
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import { sendAddedContributionMessageEmail } from '@/emails/sendEmailVariants'
|
||||
import { sendAddedContributionMessageEmail } from 'core'
|
||||
import { EventType } from '@/event/Events'
|
||||
import { userFactory } from '@/seeds/factory/user'
|
||||
import {
|
||||
@ -31,14 +30,12 @@ const interactionLogger = getLogger(
|
||||
)
|
||||
|
||||
jest.mock('@/password/EncryptorUtils')
|
||||
jest.mock('@/emails/sendEmailVariants', () => {
|
||||
const originalModule = jest.requireActual('@/emails/sendEmailVariants')
|
||||
jest.mock('core', () => {
|
||||
const originalModule = jest.requireActual('core')
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
sendAddedContributionMessageEmail: jest.fn((a) =>
|
||||
originalModule.sendAddedContributionMessageEmail(a),
|
||||
),
|
||||
sendAddedContributionMessageEmail: jest.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
@ -54,7 +51,7 @@ let testEnv: {
|
||||
let result: any
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await testEnvironment(logger, localization)
|
||||
testEnv = await testEnvironment(logger)
|
||||
mutate = testEnv.mutate
|
||||
con = testEnv.con
|
||||
db = testEnv.db
|
||||
|
||||
@ -14,7 +14,7 @@ import { Order } from '@enum/Order'
|
||||
import { ContributionMessage, ContributionMessageListResult } from '@model/ContributionMessage'
|
||||
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import { sendAddedContributionMessageEmail } from '@/emails/sendEmailVariants'
|
||||
import { sendAddedContributionMessageEmail } from 'core'
|
||||
import {
|
||||
EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE,
|
||||
EVENT_CONTRIBUTION_MESSAGE_CREATE,
|
||||
|
||||
@ -14,14 +14,13 @@ import {
|
||||
resetToken,
|
||||
testEnvironment,
|
||||
} from '@test/helpers'
|
||||
import { i18n as localization } from '@test/testSetup'
|
||||
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import {
|
||||
sendContributionConfirmedEmail,
|
||||
sendContributionDeletedEmail,
|
||||
sendContributionDeniedEmail,
|
||||
} from '@/emails/sendEmailVariants'
|
||||
} from 'core'
|
||||
import { EventType } from '@/event/Events'
|
||||
import { creations } from '@/seeds/creation/index'
|
||||
import { creationFactory } from '@/seeds/factory/creation'
|
||||
@ -55,7 +54,17 @@ import { getLogger } from 'config-schema/test/testSetup'
|
||||
import { getLogger as originalGetLogger } from 'log4js'
|
||||
import { AppDatabase } from 'database'
|
||||
|
||||
jest.mock('@/emails/sendEmailVariants')
|
||||
jest.mock('core', () => {
|
||||
const originalModule = jest.requireActual('core')
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
sendContributionDeniedEmail: jest.fn(),
|
||||
sendContributionConfirmedEmail: jest.fn(),
|
||||
sendContributionDeletedEmail: jest.fn(),
|
||||
sendEmailTranslated: jest.fn(),
|
||||
}
|
||||
})
|
||||
jest.mock('@/password/EncryptorUtils')
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`)
|
||||
@ -80,7 +89,7 @@ let contributionToDelete: any
|
||||
let bibiCreatedContribution: Contribution
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await testEnvironment(originalGetLogger('apollo'), localization)
|
||||
testEnv = await testEnvironment(originalGetLogger('apollo'))
|
||||
mutate = testEnv.mutate
|
||||
query = testEnv.query
|
||||
con = testEnv.con
|
||||
|
||||
@ -21,15 +21,15 @@ import { AdminUpdateContribution } from '@model/AdminUpdateContribution'
|
||||
import { Contribution, ContributionListResult } from '@model/Contribution'
|
||||
import { OpenCreation } from '@model/OpenCreation'
|
||||
import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
|
||||
import { TransactionTypeId } from 'core'
|
||||
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import {
|
||||
fullName,
|
||||
sendContributionChangedByModeratorEmail,
|
||||
sendContributionConfirmedEmail,
|
||||
sendContributionDeletedEmail,
|
||||
sendContributionDeniedEmail,
|
||||
} from '@/emails/sendEmailVariants'
|
||||
TransactionTypeId
|
||||
} from 'core'
|
||||
import {
|
||||
EVENT_ADMIN_CONTRIBUTION_CONFIRM,
|
||||
EVENT_ADMIN_CONTRIBUTION_CREATE,
|
||||
|
||||
@ -5,6 +5,7 @@ import { DataSource } from 'typeorm'
|
||||
|
||||
import { cleanDB, testEnvironment } from '@test/helpers'
|
||||
|
||||
import { CONFIG as CORE_CONFIG } from 'core'
|
||||
import { CONFIG } from '@/config'
|
||||
import { writeHomeCommunityEntry } from '@/seeds/community'
|
||||
import { createUser, forgotPassword, setPassword } from '@/seeds/graphql/mutations'
|
||||
@ -24,7 +25,7 @@ let testEnv: {
|
||||
|
||||
CONFIG.EMAIL_CODE_VALID_TIME = 1440
|
||||
CONFIG.EMAIL_CODE_REQUEST_TIME = 10
|
||||
CONFIG.EMAIL = false
|
||||
CORE_CONFIG.EMAIL = false
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await testEnvironment()
|
||||
|
||||
@ -2,7 +2,6 @@ import { Event as DbEvent, UserContact } from 'database'
|
||||
import { GraphQLError } from 'graphql'
|
||||
|
||||
import { cleanDB, resetToken, testEnvironment } from '@test/helpers'
|
||||
import { i18n as localization } from '@test/testSetup'
|
||||
import { getLogger } from 'config-schema/test/testSetup'
|
||||
|
||||
import { EventType } from '@/event/Events'
|
||||
@ -22,7 +21,7 @@ let con: any
|
||||
let db: AppDatabase
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await testEnvironment(logger, localization)
|
||||
testEnv = await testEnvironment(logger)
|
||||
mutate = testEnv.mutate
|
||||
con = testEnv.con
|
||||
db = testEnv.db
|
||||
|
||||
@ -950,7 +950,7 @@ describe('TransactionLinkResolver', () => {
|
||||
})
|
||||
|
||||
describe('without any filters', () => {
|
||||
it('finds 6 open transaction links and no deleted or redeemed', async () => {
|
||||
it('finds 7 open transaction links and no deleted or redeemed', async () => {
|
||||
await expect(
|
||||
query({
|
||||
query: listTransactionLinksAdmin,
|
||||
@ -960,14 +960,14 @@ describe('TransactionLinkResolver', () => {
|
||||
expect.objectContaining({
|
||||
data: {
|
||||
listTransactionLinksAdmin: {
|
||||
count: 6,
|
||||
count: 7,
|
||||
links: expect.not.arrayContaining([
|
||||
expect.objectContaining({
|
||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||
memo: 'Leider wollte niemand meine Gradidos haben :(',
|
||||
createdAt: expect.any(String),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
memo: 'Da habe ich mich wohl etwas übernommen.',
|
||||
memo: "Kein Trick, keine Zauberrei,\n bei Gradidio sei dabei!",
|
||||
deletedAt: expect.any(String),
|
||||
}),
|
||||
]),
|
||||
@ -979,7 +979,7 @@ describe('TransactionLinkResolver', () => {
|
||||
})
|
||||
|
||||
describe('all filters are null', () => {
|
||||
it('finds 6 open transaction links and no deleted or redeemed', async () => {
|
||||
it('finds 7 open transaction links and no deleted or redeemed', async () => {
|
||||
await expect(
|
||||
query({
|
||||
query: listTransactionLinksAdmin,
|
||||
@ -996,10 +996,10 @@ describe('TransactionLinkResolver', () => {
|
||||
expect.objectContaining({
|
||||
data: {
|
||||
listTransactionLinksAdmin: {
|
||||
count: 6,
|
||||
count: 7,
|
||||
links: expect.not.arrayContaining([
|
||||
expect.objectContaining({
|
||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||
memo: 'Leider wollte niemand meine Gradidos haben :(',
|
||||
createdAt: expect.any(String),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
@ -1015,7 +1015,7 @@ describe('TransactionLinkResolver', () => {
|
||||
})
|
||||
|
||||
describe('filter with deleted', () => {
|
||||
it('finds 6 open transaction links, 1 deleted, and no redeemed', async () => {
|
||||
it('finds 7 open transaction links, 1 deleted, and no redeemed', async () => {
|
||||
await expect(
|
||||
query({
|
||||
query: listTransactionLinksAdmin,
|
||||
@ -1030,10 +1030,10 @@ describe('TransactionLinkResolver', () => {
|
||||
expect.objectContaining({
|
||||
data: {
|
||||
listTransactionLinksAdmin: {
|
||||
count: 7,
|
||||
count: 8,
|
||||
links: expect.arrayContaining([
|
||||
expect.not.objectContaining({
|
||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||
memo: 'Leider wollte niemand meine Gradidos haben :(',
|
||||
createdAt: expect.any(String),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
@ -1049,7 +1049,7 @@ describe('TransactionLinkResolver', () => {
|
||||
})
|
||||
|
||||
describe('filter by expired', () => {
|
||||
it('finds 5 open transaction links, 1 expired, and no redeemed', async () => {
|
||||
it('finds 6 open transaction links, 1 expired, and no redeemed', async () => {
|
||||
await expect(
|
||||
query({
|
||||
query: listTransactionLinksAdmin,
|
||||
@ -1067,7 +1067,7 @@ describe('TransactionLinkResolver', () => {
|
||||
count: 7,
|
||||
links: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||
memo: 'Leider wollte niemand meine Gradidos haben :(',
|
||||
createdAt: expect.any(String),
|
||||
}),
|
||||
expect.not.objectContaining({
|
||||
@ -1085,7 +1085,7 @@ describe('TransactionLinkResolver', () => {
|
||||
// TODO: works not as expected, because 'redeemedAt' and 'redeemedBy' have to be added to the transaktion link factory
|
||||
|
||||
describe.skip('filter by redeemed', () => {
|
||||
it('finds 6 open transaction links, 1 deleted, and no redeemed', async () => {
|
||||
it('finds 7 open transaction links, 1 deleted, and no redeemed', async () => {
|
||||
await expect(
|
||||
query({
|
||||
query: listTransactionLinksAdmin,
|
||||
@ -1102,10 +1102,10 @@ describe('TransactionLinkResolver', () => {
|
||||
expect.objectContaining({
|
||||
data: {
|
||||
listTransactionLinksAdmin: {
|
||||
count: 6,
|
||||
count: 7,
|
||||
links: expect.arrayContaining([
|
||||
expect.not.objectContaining({
|
||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||
memo: 'Leider wollte niemand meine Gradidos haben :(',
|
||||
createdAt: expect.any(String),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
|
||||
@ -34,13 +34,14 @@ import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||
import { stephenHawking } from '@/seeds/users/stephen-hawking'
|
||||
import { getLogger } from 'config-schema/test/testSetup'
|
||||
import { CONFIG } from '@/config'
|
||||
import { CONFIG as CORE_CONFIG} from 'core'
|
||||
import { AppDatabase } from 'database'
|
||||
|
||||
jest.mock('@/password/EncryptorUtils')
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`)
|
||||
CONFIG.DLT_CONNECTOR = false
|
||||
CONFIG.EMAIL = false
|
||||
CORE_CONFIG.EMAIL = false
|
||||
|
||||
let mutate: ApolloServerTestClient['mutate']
|
||||
let query: ApolloServerTestClient['query']
|
||||
@ -75,7 +76,6 @@ let peter: User
|
||||
|
||||
let homeCom: DbCommunity
|
||||
let foreignCom: DbCommunity
|
||||
let fedForeignCom: DbFederatedCommunity
|
||||
|
||||
describe('send coins', () => {
|
||||
beforeAll(async () => {
|
||||
|
||||
@ -1,14 +1,11 @@
|
||||
import {
|
||||
AppDatabase,
|
||||
countOpenPendingTransactions,
|
||||
Community as DbCommunity,
|
||||
DltTransaction as DbDltTransaction,
|
||||
Transaction as dbTransaction,
|
||||
TransactionLink as dbTransactionLink,
|
||||
User as dbUser,
|
||||
findUserByIdentifier,
|
||||
TransactionLoggingView,
|
||||
UserLoggingView
|
||||
} from 'database'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { Args, Authorized, Ctx, Mutation, Query, Resolver } from 'type-graphql'
|
||||
@ -20,22 +17,28 @@ import { Order } from '@enum/Order'
|
||||
import { Transaction } from '@model/Transaction'
|
||||
import { TransactionList } from '@model/TransactionList'
|
||||
import { User } from '@model/User'
|
||||
import { processXComCompleteTransaction, TransactionTypeId } from 'core'
|
||||
|
||||
import {
|
||||
fullName,
|
||||
processXComCompleteTransaction,
|
||||
sendTransactionLinkRedeemedEmail,
|
||||
sendTransactionReceivedEmail,
|
||||
TransactionTypeId
|
||||
} from 'core'
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import { CONFIG } from '@/config'
|
||||
import {
|
||||
sendTransactionLinkRedeemedEmail,
|
||||
sendTransactionReceivedEmail,
|
||||
} from '@/emails/sendEmailVariants'
|
||||
import { EVENT_TRANSACTION_RECEIVE, EVENT_TRANSACTION_SEND } from '@/event/Events'
|
||||
EVENT_TRANSACTION_RECEIVE, EVENT_TRANSACTION_SEND } from '@/event/Events'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { Context, getUser } from '@/server/context'
|
||||
import { communityUser } from '@/util/communityUser'
|
||||
import { calculateBalance } from '@/util/validate'
|
||||
import { virtualDecayTransaction, virtualLinkTransaction } from '@/util/virtualTransactions'
|
||||
<<<<<<< HEAD
|
||||
import { fullName } from 'core'
|
||||
// import { TRANSACTIONS_LOCK } from 'database'
|
||||
=======
|
||||
import { TRANSACTIONS_LOCK } from 'database'
|
||||
>>>>>>> refs/remotes/origin/master
|
||||
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import { getLastTransaction } from 'database'
|
||||
|
||||
@ -21,7 +21,6 @@ import { UserContactType } from '@enum/UserContactType'
|
||||
import { ContributionLink } from '@model/ContributionLink'
|
||||
import { Location } from '@model/Location'
|
||||
import { cleanDB, headerPushMock, resetToken, testEnvironment } from '@test/helpers'
|
||||
import { i18n as localization } from '@test/testSetup'
|
||||
|
||||
import { subscribe } from '@/apis/KlicktippController'
|
||||
import { CONFIG } from '@/config'
|
||||
@ -29,7 +28,7 @@ import {
|
||||
sendAccountActivationEmail,
|
||||
sendAccountMultiRegistrationEmail,
|
||||
sendResetPasswordEmail,
|
||||
} from '@/emails/sendEmailVariants'
|
||||
} from 'core'
|
||||
import { EventType } from '@/event/Events'
|
||||
import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
import { SecretKeyCryptographyCreateKey } from '@/password/EncryptorUtils'
|
||||
@ -75,16 +74,15 @@ import { Location2Point } from './util/Location2Point'
|
||||
jest.mock('@/apis/humhub/HumHubClient')
|
||||
jest.mock('@/password/EncryptorUtils')
|
||||
|
||||
jest.mock('@/emails/sendEmailVariants', () => {
|
||||
const originalModule = jest.requireActual('@/emails/sendEmailVariants')
|
||||
jest.mock('core', () => {
|
||||
const originalModule = jest.requireActual('core')
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
sendAccountActivationEmail: jest.fn((a) => originalModule.sendAccountActivationEmail(a)),
|
||||
sendAccountMultiRegistrationEmail: jest.fn((a) =>
|
||||
originalModule.sendAccountMultiRegistrationEmail(a),
|
||||
),
|
||||
sendResetPasswordEmail: jest.fn((a) => originalModule.sendResetPasswordEmail(a)),
|
||||
sendAccountActivationEmail: jest.fn(),
|
||||
sendAccountMultiRegistrationEmail: jest.fn(),
|
||||
sendResetPasswordEmail: jest.fn(),
|
||||
sendEmailTranslated: jest.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
@ -115,7 +113,7 @@ let testEnv: {
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await testEnvironment(getLogger('apollo'), localization)
|
||||
testEnv = await testEnvironment(getLogger('apollo'))
|
||||
mutate = testEnv.mutate
|
||||
query = testEnv.query
|
||||
con = testEnv.con
|
||||
@ -160,6 +158,7 @@ describe('UserResolver', () => {
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({ data: { createUser: { id: expect.any(Number) } } }),
|
||||
)
|
||||
|
||||
})
|
||||
|
||||
describe('valid input data', () => {
|
||||
@ -1045,7 +1044,7 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('user exists in DB', () => {
|
||||
beforeAll(async () => {
|
||||
await userFactory(testEnv, bibiBloxberg)
|
||||
await userFactory(testEnv, bobBaumeister)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
@ -1055,7 +1054,7 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('duration not expired', () => {
|
||||
it('throws an error', async () => {
|
||||
await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual(
|
||||
await expect(mutate({ mutation: forgotPassword, variables: { email: 'bob@baumeister.de' } })).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [
|
||||
new GraphQLError(
|
||||
@ -1072,7 +1071,7 @@ describe('UserResolver', () => {
|
||||
describe('duration reset to 0', () => {
|
||||
it('returns true', async () => {
|
||||
CONFIG.EMAIL_CODE_REQUEST_TIME = 0
|
||||
await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual(
|
||||
await expect(mutate({ mutation: forgotPassword, variables: { email: 'bob@baumeister.de' } })).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
data: {
|
||||
forgotPassword: true,
|
||||
@ -1083,9 +1082,9 @@ describe('UserResolver', () => {
|
||||
|
||||
it('sends reset password email', () => {
|
||||
expect(sendResetPasswordEmail).toBeCalledWith({
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
email: 'bibi@bloxberg.de',
|
||||
firstName: 'Bob',
|
||||
lastName: 'der Baumeister',
|
||||
email: 'bob@baumeister.de',
|
||||
language: 'de',
|
||||
resetLink: expect.any(String),
|
||||
timeDurationObject: expect.objectContaining({
|
||||
@ -1097,7 +1096,7 @@ describe('UserResolver', () => {
|
||||
|
||||
it('stores the EMAIL_FORGOT_PASSWORD event in the database', async () => {
|
||||
const userConatct = await UserContact.findOneOrFail({
|
||||
where: { email: 'bibi@bloxberg.de' },
|
||||
where: { email: 'bob@baumeister.de' },
|
||||
relations: ['user'],
|
||||
})
|
||||
await expect(DbEvent.find()).resolves.toContainEqual(
|
||||
@ -1113,7 +1112,7 @@ describe('UserResolver', () => {
|
||||
describe('request reset password again', () => {
|
||||
it('throws an error', async () => {
|
||||
CONFIG.EMAIL_CODE_REQUEST_TIME = emailCodeRequestTime
|
||||
await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual(
|
||||
await expect(mutate({ mutation: forgotPassword, variables: { email: 'bob@baumeister.de' } })).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('Email already sent less than 10 minutes ago')],
|
||||
}),
|
||||
@ -1133,8 +1132,8 @@ describe('UserResolver', () => {
|
||||
let emailContact: UserContact
|
||||
|
||||
beforeAll(async () => {
|
||||
await userFactory(testEnv, bibiBloxberg)
|
||||
emailContact = await UserContact.findOneOrFail({ where: { email: bibiBloxberg.email } })
|
||||
await userFactory(testEnv, bobBaumeister)
|
||||
emailContact = await UserContact.findOneOrFail({ where: { email: bobBaumeister.email } })
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
@ -1145,7 +1144,7 @@ describe('UserResolver', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
query({ query: queryOptIn, variables: { optIn: 'not-valid' } }),
|
||||
query({ query: queryOptIn, variables: { email: 'bob@baumeister.de', optIn: 'not-valid' } }),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [
|
||||
@ -1166,7 +1165,7 @@ describe('UserResolver', () => {
|
||||
await expect(
|
||||
query({
|
||||
query: queryOptIn,
|
||||
variables: { optIn: emailContact.emailVerificationCode.toString() },
|
||||
variables: { email: 'bob@baumeister.de', optIn: emailContact.emailVerificationCode.toString() },
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
|
||||
@ -10,7 +10,6 @@ import {
|
||||
findUserByIdentifier
|
||||
} from 'database'
|
||||
import { GraphQLResolveInfo } from 'graphql'
|
||||
import i18n from 'i18n'
|
||||
import {
|
||||
Arg,
|
||||
Args,
|
||||
@ -57,11 +56,6 @@ import { encode } from '@/auth/JWT'
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import { CONFIG } from '@/config'
|
||||
import { PublishNameLogic } from '@/data/PublishName.logic'
|
||||
import {
|
||||
sendAccountActivationEmail,
|
||||
sendAccountMultiRegistrationEmail,
|
||||
sendResetPasswordEmail,
|
||||
} from '@/emails/sendEmailVariants'
|
||||
import {
|
||||
EVENT_ADMIN_USER_DELETE,
|
||||
EVENT_ADMIN_USER_ROLE_SET,
|
||||
@ -85,8 +79,12 @@ import { Context, getClientTimezoneOffset, getUser } from '@/server/context'
|
||||
import { communityDbUser } from '@/util/communityUser'
|
||||
import { hasElopageBuys } from '@/util/hasElopageBuys'
|
||||
import { durationInMinutesFromDates, getTimeDurationObject, printTimeDuration } from '@/util/time'
|
||||
import { delay } from 'core'
|
||||
|
||||
import {
|
||||
delay,
|
||||
sendAccountActivationEmail,
|
||||
sendAccountMultiRegistrationEmail,
|
||||
sendResetPasswordEmail,
|
||||
} from 'core'
|
||||
import random from 'random-bigint'
|
||||
import { randombytes_random } from 'sodium-native'
|
||||
|
||||
@ -233,7 +231,6 @@ export class UserResolver {
|
||||
logger.debug('validation of login credentials successful...')
|
||||
|
||||
const user = new User(dbUser)
|
||||
i18n.setLocale(user.language)
|
||||
|
||||
// Elopage Status & Stored PublisherId
|
||||
user.hasElopage = await this.hasElopage({ ...context, user: dbUser })
|
||||
@ -322,7 +319,6 @@ export class UserResolver {
|
||||
if (!language || !isLanguage(language)) {
|
||||
language = DEFAULT_LANGUAGE
|
||||
}
|
||||
i18n.setLocale(language)
|
||||
|
||||
// check if user with email still exists?
|
||||
email = email.trim().toLowerCase()
|
||||
@ -764,7 +760,6 @@ export class UserResolver {
|
||||
throw new LogError('Given language is not a valid language or not supported')
|
||||
}
|
||||
user.language = language
|
||||
i18n.setLocale(language)
|
||||
updated = true
|
||||
}
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
|
||||
import { bobBaumeister } from '@/seeds/users/bob-baumeister'
|
||||
import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||
import { CONFIG } from '@/config'
|
||||
import { CONFIG as CORE_CONFIG } from 'core'
|
||||
// import { TRANSACTIONS_LOCK } from 'database'
|
||||
import { Mutex } from 'redis-semaphore'
|
||||
import { AppDatabase } from 'database'
|
||||
@ -29,7 +30,7 @@ import { AppDatabase } from 'database'
|
||||
jest.mock('@/password/EncryptorUtils')
|
||||
|
||||
CONFIG.DLT_CONNECTOR = false
|
||||
CONFIG.EMAIL = false
|
||||
CORE_CONFIG.EMAIL = false
|
||||
|
||||
let mutate: ApolloServerTestClient['mutate']
|
||||
let con: DataSource
|
||||
|
||||
@ -39,7 +39,7 @@ export const transactionLinkFactory = async (
|
||||
}
|
||||
|
||||
if (transactionLink.deletedAt) {
|
||||
dbTransactionLink.deletedAt = new Date()
|
||||
dbTransactionLink.deletedAt = new Date(dbTransactionLink.createdAt.getTime() + 1000)
|
||||
await dbTransactionLink.save()
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +18,6 @@ export const userFactory = async (
|
||||
// console.log('call createUser with', JSON.stringify(user, null, 2))
|
||||
const response = await mutate({ mutation: createUser, variables: user })
|
||||
if (!response?.data?.createUser) {
|
||||
// biome-ignore lint/suspicious/noConsole: will be used in tests where logging is mocked
|
||||
// console.log(JSON.stringify(response, null, 2))
|
||||
throw new Error('createUser mutation returned unexpected response')
|
||||
}
|
||||
@ -40,11 +39,15 @@ export const userFactory = async (
|
||||
}
|
||||
|
||||
// get last changes of user from database
|
||||
dbUser = await User.findOneOrFail({ where: { id }, relations: ['userRoles'] })
|
||||
dbUser = await User.findOneOrFail({ where: { id }, relations: { userRoles: true, emailContact: true } })
|
||||
|
||||
if (user.createdAt || user.deletedAt || user.role) {
|
||||
if (user.createdAt) {
|
||||
dbUser.createdAt = user.createdAt
|
||||
// make sure emailContact is also updated for e2e test, prevent failing when time between seeding and test run is < 1 minute
|
||||
dbUser.emailContact.createdAt = user.createdAt
|
||||
dbUser.emailContact.updatedAt = user.createdAt
|
||||
await dbUser.emailContact.save()
|
||||
}
|
||||
if (user.deletedAt) {
|
||||
dbUser.deletedAt = user.deletedAt
|
||||
|
||||
@ -3,6 +3,7 @@ import { entities } from 'database'
|
||||
import { datatype, internet, name } from 'faker'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
import { CONFIG as CORE_CONFIG } from 'core'
|
||||
import { createServer } from '@/server/createServer'
|
||||
|
||||
import { initLogging } from '@/server/logger'
|
||||
@ -17,7 +18,7 @@ import { userFactory } from './factory/user'
|
||||
import { transactionLinks } from './transactionLink/index'
|
||||
import { users } from './users/index'
|
||||
|
||||
CONFIG.EMAIL = false
|
||||
CORE_CONFIG.EMAIL = false
|
||||
const logger = getLogger('seed')
|
||||
|
||||
const context = {
|
||||
|
||||
@ -4,8 +4,7 @@ export const transactionLinks: TransactionLinkInterface[] = [
|
||||
{
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 19.99,
|
||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||
createdAt: new Date(2022, 0, 1),
|
||||
memo: 'Leider wollte niemand meine Gradidos haben :(',
|
||||
},
|
||||
{
|
||||
email: 'bibi@bloxberg.de',
|
||||
|
||||
@ -9,4 +9,6 @@ export const bibiBloxberg: UserInterface = {
|
||||
emailChecked: true,
|
||||
language: 'de',
|
||||
publisherId: 1234,
|
||||
// move user createdAt before transaction link
|
||||
createdAt: new Date(2021, 9, 17),
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { CONFIG } from '@/config'
|
||||
import { CONFIG as CORE_CONFIG } from 'core'
|
||||
import { schema } from '@/graphql/schema'
|
||||
import { elopageWebhook } from '@/webhook/elopage'
|
||||
import { gmsWebhook } from '@/webhook/gms'
|
||||
@ -29,7 +30,6 @@ interface ServerDef {
|
||||
export const createServer = async (
|
||||
apolloLogger: Logger,
|
||||
context: any = serverContext,
|
||||
localization: i18n.I18n = i18n,
|
||||
): Promise<ServerDef> => {
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.createServer`)
|
||||
logger.debug('createServer...')
|
||||
@ -74,9 +74,9 @@ export const createServer = async (
|
||||
app.use(json())
|
||||
// bodyparser urlencoded for elopage
|
||||
app.use(urlencoded({ extended: true }))
|
||||
|
||||
|
||||
// i18n
|
||||
app.use(localization.init)
|
||||
app.use(i18n.init)
|
||||
|
||||
// Elopage Webhook
|
||||
|
||||
@ -101,7 +101,7 @@ export const createServer = async (
|
||||
})
|
||||
apollo.applyMiddleware({ app, path: '/' })
|
||||
logger.info(
|
||||
`running with PRODUCTION=${CONFIG.PRODUCTION}, sending EMAIL enabled=${CONFIG.EMAIL} and EMAIL_TEST_MODUS=${CONFIG.EMAIL_TEST_MODUS} ...`,
|
||||
`running with PRODUCTION=${CONFIG.PRODUCTION}, sending EMAIL enabled=${CORE_CONFIG.EMAIL} and EMAIL_TEST_MODUS=${CORE_CONFIG.EMAIL_TEST_MODUS} ...`,
|
||||
)
|
||||
logger.debug('createServer...successful')
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import path from 'node:path'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import i18n from 'i18n'
|
||||
import { getLogger } from 'log4js'
|
||||
@ -9,7 +8,10 @@ i18n.configure({
|
||||
locales: ['en', 'de'],
|
||||
defaultLocale: 'en',
|
||||
retryInDefaultLocale: false,
|
||||
directory: path.join(__dirname, '..', 'locales'),
|
||||
staticCatalog: {
|
||||
en: { general: { decimalSeparator: "." } },
|
||||
de: { general: { decimalSeparator: "," } },
|
||||
},
|
||||
// autoReload: true, // if this is activated the seeding hangs at the very end
|
||||
updateFiles: false,
|
||||
objectNotation: true,
|
||||
|
||||
@ -3,8 +3,6 @@ import { entities } from 'database'
|
||||
|
||||
import { createServer } from '@/server/createServer'
|
||||
|
||||
import { i18n } from './testSetup'
|
||||
|
||||
import { getLogger } from 'log4js'
|
||||
|
||||
export const headerPushMock = jest.fn((t) => {
|
||||
@ -29,8 +27,8 @@ export const cleanDB = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
export const testEnvironment = async (testLogger = getLogger('apollo'), testI18n = i18n) => {
|
||||
const server = await createServer( testLogger, context, testI18n)
|
||||
export const testEnvironment = async (testLogger = getLogger('apollo')) => {
|
||||
const server = await createServer( testLogger, context)
|
||||
const con = server.con
|
||||
const testClient = createTestClient(server.apollo)
|
||||
const mutate = testClient.mutate
|
||||
|
||||
@ -1,27 +1,13 @@
|
||||
import 'openai/shims/node'
|
||||
import { CONFIG } from '@/config'
|
||||
import { i18n } from '@/server/localization'
|
||||
import { CONFIG as CORE_CONFIG } from 'core'
|
||||
import { getLogger, printLogs, clearLogs } from 'config-schema/test/testSetup'
|
||||
|
||||
CONFIG.EMAIL = true
|
||||
CONFIG.EMAIL_TEST_MODUS = false
|
||||
CORE_CONFIG.EMAIL = false
|
||||
CORE_CONFIG.EMAIL_TEST_MODUS = false
|
||||
CONFIG.HUMHUB_ACTIVE = false
|
||||
CONFIG.GMS_ACTIVE = false
|
||||
|
||||
jest.setTimeout(1000000)
|
||||
|
||||
jest.mock('@/server/localization', () => {
|
||||
const originalModule = jest.requireActual<typeof i18n>('@/server/localization')
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
i18n: {
|
||||
init: jest.fn(),
|
||||
// configure: jest.fn(),
|
||||
// __: jest.fn(),
|
||||
// setLocale: jest.fn(),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
export { i18n, getLogger, printLogs, clearLogs as cleanLogs }
|
||||
export { getLogger, printLogs, clearLogs as cleanLogs }
|
||||
|
||||
@ -63,7 +63,7 @@
|
||||
"typeRoots": [ /* List of folders to include type definitions from. */
|
||||
"@types",
|
||||
"node_modules/@types",
|
||||
"../node_modules/@types"
|
||||
"../node_modules/@types",
|
||||
],
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
@ -86,6 +86,9 @@
|
||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
|
||||
},
|
||||
"include": [
|
||||
"../core/src/types"
|
||||
],
|
||||
"ts-node": {
|
||||
"swc": true
|
||||
}
|
||||
|
||||
@ -8,10 +8,8 @@
|
||||
"locales": {},
|
||||
"locales:fix": {},
|
||||
"lint": {
|
||||
"dependsOn": ["locales"]
|
||||
},
|
||||
"lint:fix": {
|
||||
"dependsOn": ["locales:fix"]
|
||||
},
|
||||
"test": {
|
||||
"dependsOn": ["database#up:backend_test", "^build"]
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "config-schema",
|
||||
"version": "2.7.0",
|
||||
"version": "2.7.1",
|
||||
"description": "Gradido Config for validate config",
|
||||
"main": "./build/index.js",
|
||||
"types": "./src/index.ts",
|
||||
|
||||
@ -17,17 +17,23 @@ export function validate(schema: ObjectSchema, data: any) {
|
||||
throw new Error('missing key in config validation with joi: ' + details)
|
||||
}
|
||||
const value = err.context.value
|
||||
const description = schemaJson.keys[key]
|
||||
? schema.describe().keys[key].flags.description
|
||||
: 'No description available'
|
||||
if (data[key] === undefined) {
|
||||
throw new Error(
|
||||
`Environment Variable '${key}' is missing. ${description}, details: ${details}`,
|
||||
)
|
||||
} else {
|
||||
throw new Error(
|
||||
`Error on Environment Variable ${key} with value = ${value}: ${err.message}. ${description}`,
|
||||
)
|
||||
try {
|
||||
const description = schemaJson.keys[key]
|
||||
? schema.describe().keys[key].flags.description
|
||||
: 'No description available'
|
||||
if (data[key] === undefined) {
|
||||
throw new Error(
|
||||
`Environment Variable '${key}' is missing. ${description}, details: ${details}`,
|
||||
)
|
||||
} else {
|
||||
throw new Error(
|
||||
`Error on Environment Variable ${key} with value = ${value}: ${err.message}. ${description}`,
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
// biome-ignore lint/suspicious/noConsole: schema validation may be run before logger is initialized
|
||||
console.error('Error getting description for key ' + key + ': ' + e)
|
||||
throw e
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -91,7 +91,8 @@ const getLoggerMocked = mock().mockImplementation((param: any) => {
|
||||
})
|
||||
|
||||
mock.module('log4js', () => ({
|
||||
getLogger: getLoggerMocked
|
||||
getLogger: getLoggerMocked,
|
||||
addLayout: jest.fn()
|
||||
}))
|
||||
|
||||
export function getLogger(name: string) {
|
||||
|
||||
16
core/esbuild.config.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { build } from 'esbuild'
|
||||
|
||||
build({
|
||||
entryPoints: ['src/index.ts'],
|
||||
outdir: 'build',
|
||||
platform: 'node',
|
||||
target: 'node18.20.7',
|
||||
loader: {
|
||||
'.png': 'binary',
|
||||
'.jpeg': 'binary',
|
||||
'.jpg': 'binary',
|
||||
},
|
||||
bundle: true,
|
||||
sourcemap: true,
|
||||
packages: 'external',
|
||||
})
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "core",
|
||||
"version": "2.7.0",
|
||||
"version": "2.7.1",
|
||||
"description": "Gradido Core Code, High-Level Shared Code, with dependencies on other modules",
|
||||
"main": "./build/index.js",
|
||||
"types": "./src/index.ts",
|
||||
@ -15,22 +15,27 @@
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "esbuild src/index.ts --outdir=build --platform=node --target=node18.20.7 --bundle --packages=external",
|
||||
"build": "bun esbuild.config.ts && mkdirp build/templates/ && ncp src/emails/templates build/templates",
|
||||
"build:bun": "bun build src/index.ts --outdir=build --target=bun --packages=external",
|
||||
"test": "bun test",
|
||||
"test:debug": "bun test --inspect-brk",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"lint": "biome check --error-on-warnings .",
|
||||
"lint:fix": "biome check --error-on-warnings . --write",
|
||||
"locales": "scripts/sort.sh src/emails/locales",
|
||||
"locales:fix": "scripts/sort.sh src/emails/locales --fix",
|
||||
"clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo"
|
||||
},
|
||||
"dependencies": {
|
||||
"database": "*",
|
||||
"email-templates": "^10.0.1",
|
||||
"esbuild": "^0.25.2",
|
||||
"i18n": "^0.15.1",
|
||||
"joi": "^17.13.3",
|
||||
"jose": "^4.14.4",
|
||||
"log4js": "^6.9.1",
|
||||
"nodemailer": "^6.6.5",
|
||||
"pug": "^3.0.2",
|
||||
"redis-semaphore": "^5.6.2",
|
||||
"shared": "*",
|
||||
"sodium-native": "^3.4.1",
|
||||
@ -38,15 +43,19 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.0.0",
|
||||
"@types/email-templates": "^10.0.4",
|
||||
"@types/i18n": "^0.13.4",
|
||||
"@types/minimatch": "6.0.0",
|
||||
"@types/node": "^17.0.21",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"@types/sodium-native": "^2.3.5",
|
||||
"config-schema": "*",
|
||||
"decimal.js-light": "^2.5.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"graphql-request": "5.0.0",
|
||||
"jest": "27.2.4",
|
||||
"mkdirp": "^3.0.1",
|
||||
"ncp": "^2.0.0",
|
||||
"type-graphql": "^1.1.1",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
|
||||
@ -4,11 +4,11 @@ ROOT_DIR=$(dirname "$0")/..
|
||||
|
||||
exit_code=0
|
||||
|
||||
for locale_file in $ROOT_DIR/src/locales/*.json
|
||||
for locale_file in $ROOT_DIR/"$1"/*.json
|
||||
do
|
||||
jq -M 'to_entries | sort_by(.key) | from_entries' "$locale_file" > tmp.json
|
||||
|
||||
if [ "$*" == "--fix" ]
|
||||
if [ "$2" == "--fix" ]
|
||||
then
|
||||
mv tmp.json "$locale_file"
|
||||
else
|
||||
@ -20,8 +20,34 @@ const federation = {
|
||||
),
|
||||
}
|
||||
|
||||
const COMMUNITY_HOST = process.env.COMMUNITY_HOST ?? 'localhost'
|
||||
const URL_PROTOCOL = process.env.URL_PROTOCOL ?? 'http'
|
||||
const COMMUNITY_URL = process.env.COMMUNITY_URL ?? `${URL_PROTOCOL}://${COMMUNITY_HOST}`
|
||||
|
||||
const community = {
|
||||
COMMUNITY_SUPPORT_MAIL: process.env.COMMUNITY_SUPPORT_MAIL ?? 'support@supportmail.com',
|
||||
COMMUNITY_URL,
|
||||
}
|
||||
|
||||
|
||||
const email = {
|
||||
EMAIL: process.env.EMAIL === 'true',
|
||||
EMAIL_LINK_FORGOTPASSWORD:
|
||||
COMMUNITY_URL + (process.env.EMAIL_LINK_FORGOTPASSWORD_PATH ?? '/forgot-password'),
|
||||
EMAIL_TLS: process.env.EMAIL_TLS !== 'false',
|
||||
EMAIL_TEST_MODUS: process.env.EMAIL_TEST_MODUS === 'true',
|
||||
EMAIL_TEST_RECEIVER: process.env.EMAIL_TEST_RECEIVER ?? 'stage1@gradido.net',
|
||||
EMAIL_USERNAME: process.env.EMAIL_USERNAME ?? '',
|
||||
EMAIL_SENDER: process.env.EMAIL_SENDER ?? 'info@gradido.net',
|
||||
EMAIL_PASSWORD: process.env.EMAIL_PASSWORD ?? '',
|
||||
EMAIL_SMTP_HOST: process.env.EMAIL_SMTP_HOST ?? 'mailserver',
|
||||
EMAIL_SMTP_PORT: Number(process.env.EMAIL_SMTP_PORT) || 1025,
|
||||
}
|
||||
|
||||
|
||||
export const CONFIG = {
|
||||
...federation,
|
||||
...community,
|
||||
...email,
|
||||
}
|
||||
validate(schema, CONFIG)
|
||||
|
||||
@ -1,6 +1,93 @@
|
||||
|
||||
import Joi from 'joi'
|
||||
import { COMMUNITY_SUPPORT_MAIL, COMMUNITY_URL, NODE_ENV } from 'config-schema'
|
||||
|
||||
export const schema = Joi.object({
|
||||
COMMUNITY_SUPPORT_MAIL,
|
||||
COMMUNITY_URL,
|
||||
NODE_ENV,
|
||||
|
||||
EMAIL: Joi.boolean()
|
||||
.default(false)
|
||||
.description('Enable or disable email functionality')
|
||||
.required(),
|
||||
|
||||
EMAIL_LINK_FORGOTPASSWORD: Joi.string()
|
||||
.uri({ scheme: ['http', 'https'] })
|
||||
.custom((value: string, helpers: Joi.CustomHelpers<string>): string | Joi.ErrorReport => {
|
||||
if (!value.startsWith(helpers.state.ancestors[0].COMMUNITY_URL)) {
|
||||
return helpers.error('string.pattern.base', { value, communityUrl: COMMUNITY_URL })
|
||||
}
|
||||
return value
|
||||
})
|
||||
.description('Email Verification link for set new Password, when old Password was forgotten.')
|
||||
.required(),
|
||||
|
||||
EMAIL_TEST_MODUS: Joi.boolean()
|
||||
.default(false)
|
||||
.description('When enabled, all emails are sended to EMAIL_TEST_RECEIVER')
|
||||
.optional(),
|
||||
|
||||
EMAIL_TEST_RECEIVER: Joi.string()
|
||||
.email()
|
||||
.default('stage1@gradido.net')
|
||||
.when('EMAIL_TEST_MODUS', { is: true, then: Joi.required() })
|
||||
.description('Email address used in test mode'),
|
||||
|
||||
EMAIL_USERNAME: Joi.alternatives().conditional(Joi.ref('EMAIL'), {
|
||||
is: true,
|
||||
then: Joi.alternatives().conditional(Joi.ref('NODE_ENV'), {
|
||||
is: 'development',
|
||||
then: Joi.string()
|
||||
.allow('')
|
||||
.description('Username for SMTP authentication (optional in development)'),
|
||||
otherwise: Joi.string()
|
||||
.pattern(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)
|
||||
.description('Valid SMTP username required in production')
|
||||
.required(),
|
||||
}),
|
||||
otherwise: Joi.string().allow('').optional(),
|
||||
}),
|
||||
|
||||
EMAIL_SENDER: Joi.string()
|
||||
.email()
|
||||
.when('EMAIL', { is: true, then: Joi.required() })
|
||||
.default('info@gradido.net')
|
||||
.description('Email address used as sender'),
|
||||
|
||||
EMAIL_PASSWORD: Joi.alternatives().conditional(Joi.ref('EMAIL'), {
|
||||
is: true,
|
||||
then: Joi.alternatives().conditional(Joi.ref('NODE_ENV'), {
|
||||
is: 'development',
|
||||
then: Joi.string()
|
||||
.allow('')
|
||||
.description('Password for SMTP authentication (optional in development)'),
|
||||
otherwise: Joi.string()
|
||||
.min(8)
|
||||
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&#]).{8,}$/)
|
||||
.description(
|
||||
'Password must be at least 8 characters long, include uppercase and lowercase letters, a number, and a special character',
|
||||
)
|
||||
.required(),
|
||||
}),
|
||||
otherwise: Joi.string().allow('').optional(),
|
||||
}),
|
||||
|
||||
EMAIL_SMTP_HOST: Joi.string()
|
||||
.hostname()
|
||||
.when('EMAIL', { is: true, then: Joi.required() })
|
||||
.default('mailserver')
|
||||
.description('SMTP server hostname'),
|
||||
|
||||
EMAIL_SMTP_PORT: Joi.number()
|
||||
.integer()
|
||||
.positive()
|
||||
.when('EMAIL', { is: true, then: Joi.required() })
|
||||
.default(1025)
|
||||
.description('SMTP server port'),
|
||||
|
||||
EMAIL_TLS: Joi.boolean().default(true).description('Enable or disable TLS for SMTP').optional(),
|
||||
|
||||
FEDERATION_BACKEND_SEND_ON_API: Joi.string()
|
||||
.pattern(/^\d+_\d+$/)
|
||||
.default('1_0')
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
|
||||
exports[`sendEmailVariants sendAccountActivationEmail result has the correct html as snapshot 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\\"en\\">
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta content=\\"multipart/html; charset=UTF-8\\" http-equiv=\\"content-type\\">
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1\\">
|
||||
<meta content=\"multipart/html; charset=UTF-8\" http-equiv=\"content-type\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<style>
|
||||
.wf-force-outline-none[tabindex=\\"-1\\"]:focus {
|
||||
.wf-force-outline-none[tabindex=\"-1\"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
@ -133,41 +133,41 @@ exports[`sendEmailVariants sendAccountActivationEmail result has the correct htm
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style=\\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\\">
|
||||
<div class=\\"container\\" style=\\"max-width: 680px; margin: 0 auto; display: block;\\">
|
||||
<body style=\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\">
|
||||
<div class=\"container\" style=\"max-width: 680px; margin: 0 auto; display: block;\">
|
||||
<header>
|
||||
<div class=\\"head\\"><img class=\\"head-logo\\" alt=\\"Gradido Logo\\" loading=\\"lazy\\" src=\\"cid:gradidoheader\\" style=\\"width: 100%; height: auto;\\"></div>
|
||||
<div class=\"head\"><img class=\"head-logo\" alt=\"Gradido Logo\" loading=\"lazy\" src=\"cid:gradidoheader\" style=\"width: 100%; height: auto;\"></div>
|
||||
</header>
|
||||
<div class=\\"wrapper\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Email Verification</h2>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"wrapper\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Email Verification</h2>
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Hello Peter Lustig,</p>
|
||||
<p>Your email address has just been registered with Gradido.</p>
|
||||
</div>
|
||||
<div class=\\"content\\" style=\\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Complete registration</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Please click here to complete the registration and activate your Gradido account.</div><a class=\\"button-3\\" href=\\"http://localhost/checkEmail/6627633878930542284\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\\">Activate account</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Or copy the link into your browser window.</div><a class=\\"clink\\" href=\\"http://localhost/checkEmail/6627633878930542284\\" style=\\"line-break: anywhere; margin-bottom: 40px;\\">http://localhost/checkEmail/6627633878930542284</a>
|
||||
<div class=\"content\" style=\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Complete registration</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Please click here to complete the registration and activate your Gradido account.</div><a class=\"button-3\" href=\"http://localhost/checkEmail/6627633878930542284\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\">Activate account</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Or copy the link into your browser window.</div><a class=\"clink\" href=\"http://localhost/checkEmail/6627633878930542284\" style=\"line-break: anywhere; margin-bottom: 40px;\">http://localhost/checkEmail/6627633878930542284</a>
|
||||
<requestnewlink>
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Request new valid link</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">The link has a validity of 23 hours and 30 minutes.
|
||||
If the validity of the link has already expired, you can have a new link sent to you here.</div><a class=\\"button-4\\" href=\\"http://localhost/forgot-password\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%; background-image: radial-gradient(circle farthest-corner at 0% 0%, #616161, #c2c2c2);\\">New link</a>
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Request new valid link</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">The link has a validity of 23 hours and 30 minutes.
|
||||
If the validity of the link has already expired, you can have a new link sent to you here.</div><a class=\"button-4\" href=\"http://localhost/forgot-password\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%; background-image: radial-gradient(circle farthest-corner at 0% 0%, #616161, #c2c2c2);\">New link</a>
|
||||
</requestnewlink>
|
||||
</div>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Kind regards,<br>your Gradido team
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class=\\"w-container footer_01\\">
|
||||
<div class=\\"socialmedia\\" style=\\"display: flex; margin-top: 40px; max-width: 600px;\\"><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.facebook.com/groups/Gradido/\\" style=\\"width: 150px;\\"><img class=\\"bi-facebook\\" alt=\\"facebook\\" loading=\\"lazy\\" src=\\"cid:facebookicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://t.me/GradidoGruppe\\" style=\\"width: 150px;\\"><img class=\\"bi-telegram\\" alt=\\"Telegram\\" loading=\\"lazy\\" src=\\"cid:telegramicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://twitter.com/gradido\\" style=\\"width: 150px;\\"><img class=\\"bi-twitter\\" alt=\\"Twitter\\" loading=\\"lazy\\" src=\\"cid:twittericon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.youtube.com/c/GradidoNet\\" style=\\"width: 150px;\\"><img class=\\"bi-youtube\\" alt=\\"youtube\\" loading=\\"lazy\\" src=\\"cid:youtubeicon\\"></a></div>
|
||||
<div class=\\"line\\" style=\\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\\"></div>
|
||||
<div class=\\"footer\\" style=\\"padding-bottom: 20px;\\">
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">If you have any further questions, please contact our support.</div><a class=\\"footer_p2\\" href=\\"mailto:support@gradido.net\\" style=\\"color: #383838; font-weight: bold;\\">support@gradido.net</a>
|
||||
<div> <img class=\\"image\\" alt=\\"Gradido Logo\\" src=\\"https://gdd.gradido.net/img/brand/green.png\\" style=\\"width: 200px; margin-top: 30px; margin-bottom: 30px;\\" width=\\"200\\"></div>
|
||||
<div><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/impressum/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Impressum</a></div><br><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/datenschutz/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Privacy Policy</a>
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
<div class=\"w-container footer_01\">
|
||||
<div class=\"socialmedia\" style=\"display: flex; margin-top: 40px; max-width: 600px;\"><a class=\"slink\" target=\"_blank\" href=\"https://www.facebook.com/groups/Gradido/\" style=\"width: 150px;\"><img class=\"bi-facebook\" alt=\"facebook\" loading=\"lazy\" src=\"cid:facebookicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://t.me/GradidoGruppe\" style=\"width: 150px;\"><img class=\"bi-telegram\" alt=\"Telegram\" loading=\"lazy\" src=\"cid:telegramicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://twitter.com/gradido\" style=\"width: 150px;\"><img class=\"bi-twitter\" alt=\"Twitter\" loading=\"lazy\" src=\"cid:twittericon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://www.youtube.com/c/GradidoNet\" style=\"width: 150px;\"><img class=\"bi-youtube\" alt=\"youtube\" loading=\"lazy\" src=\"cid:youtubeicon\"></a></div>
|
||||
<div class=\"line\" style=\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\"></div>
|
||||
<div class=\"footer\" style=\"padding-bottom: 20px;\">
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">If you have any further questions, please contact our support.</div><a class=\"footer_p2\" href=\"mailto:support@gradido.net\" style=\"color: #383838; font-weight: bold;\">support@gradido.net</a>
|
||||
<div> <img class=\"image\" alt=\"Gradido Logo\" src=\"https://gdd.gradido.net/img/brand/green.png\" style=\"width: 200px; margin-top: 30px; margin-bottom: 30px;\" width=\"200\"></div>
|
||||
<div><a class=\"terms_of_use\" href=\"https://gradido.net/de/impressum/\" target=\"_blank\" style=\"color: #9ca0a8;\">Impressum</a></div><br><a class=\"terms_of_use\" href=\"https://gradido.net/de/datenschutz/\" target=\"_blank\" style=\"color: #9ca0a8;\">Privacy Policy</a>
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@ -178,12 +178,12 @@ If the validity of the link has already expired, you can have a new link sent to
|
||||
|
||||
exports[`sendEmailVariants sendAccountMultiRegistrationEmail calls "sendEmailTranslated" result has the correct html as snapshot 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\\"en\\">
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta content=\\"multipart/html; charset=UTF-8\\" http-equiv=\\"content-type\\">
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1\\">
|
||||
<meta content=\"multipart/html; charset=UTF-8\" http-equiv=\"content-type\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<style>
|
||||
.wf-force-outline-none[tabindex=\\"-1\\"]:focus {
|
||||
.wf-force-outline-none[tabindex=\"-1\"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
@ -309,39 +309,39 @@ exports[`sendEmailVariants sendAccountMultiRegistrationEmail calls "sendEmailTra
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style=\\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\\">
|
||||
<div class=\\"container\\" style=\\"max-width: 680px; margin: 0 auto; display: block;\\">
|
||||
<body style=\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\">
|
||||
<div class=\"container\" style=\"max-width: 680px; margin: 0 auto; display: block;\">
|
||||
<header>
|
||||
<div class=\\"head\\"><img class=\\"head-logo\\" alt=\\"Gradido Logo\\" loading=\\"lazy\\" src=\\"cid:gradidoheader\\" style=\\"width: 100%; height: auto;\\"></div>
|
||||
<div class=\"head\"><img class=\"head-logo\" alt=\"Gradido Logo\" loading=\"lazy\" src=\"cid:gradidoheader\" style=\"width: 100%; height: auto;\"></div>
|
||||
</header>
|
||||
<div class=\\"wrapper\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Try To Register Again With Your Email</h2>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"wrapper\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Try To Register Again With Your Email</h2>
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Hello Peter Lustig,</p>
|
||||
<p>Your email address has just been used again to register an account with Gradido.<br>However, an account already exists for your email address.
|
||||
</p>
|
||||
</div>
|
||||
<div class=\\"content\\" style=\\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Reset password</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">If you have forgotten your password, please click here.</div><a class=\\"button-3\\" href=\\"http://localhost/forgot-password\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\\">reset</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Or copy the link into your browser window.</div><a class=\\"clink\\" href=\\"http://localhost/forgot-password\\" style=\\"line-break: anywhere; margin-bottom: 40px;\\">http://localhost/forgot-password</a>
|
||||
<h2 style=\\"margin-top: 15px; color: red;\\">Contact support</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">If you did not try to register again, please contact our support:</div><a class=\\"clink\\" href=\\"mailto:support@supportmail.com\\" style=\\"line-break: anywhere; margin-bottom: 40px;\\">support@supportmail.com</a>
|
||||
<div class=\"content\" style=\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Reset password</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">If you have forgotten your password, please click here.</div><a class=\"button-3\" href=\"http://localhost/forgot-password\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\">reset</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Or copy the link into your browser window.</div><a class=\"clink\" href=\"http://localhost/forgot-password\" style=\"line-break: anywhere; margin-bottom: 40px;\">http://localhost/forgot-password</a>
|
||||
<h2 style=\"margin-top: 15px; color: red;\">Contact support</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">If you did not try to register again, please contact our support:</div><a class=\"clink\" href=\"mailto:support@supportmail.com\" style=\"line-break: anywhere; margin-bottom: 40px;\">support@supportmail.com</a>
|
||||
</div>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Kind regards,<br>your Gradido team
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class=\\"w-container footer_01\\">
|
||||
<div class=\\"socialmedia\\" style=\\"display: flex; margin-top: 40px; max-width: 600px;\\"><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.facebook.com/groups/Gradido/\\" style=\\"width: 150px;\\"><img class=\\"bi-facebook\\" alt=\\"facebook\\" loading=\\"lazy\\" src=\\"cid:facebookicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://t.me/GradidoGruppe\\" style=\\"width: 150px;\\"><img class=\\"bi-telegram\\" alt=\\"Telegram\\" loading=\\"lazy\\" src=\\"cid:telegramicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://twitter.com/gradido\\" style=\\"width: 150px;\\"><img class=\\"bi-twitter\\" alt=\\"Twitter\\" loading=\\"lazy\\" src=\\"cid:twittericon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.youtube.com/c/GradidoNet\\" style=\\"width: 150px;\\"><img class=\\"bi-youtube\\" alt=\\"youtube\\" loading=\\"lazy\\" src=\\"cid:youtubeicon\\"></a></div>
|
||||
<div class=\\"line\\" style=\\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\\"></div>
|
||||
<div class=\\"footer\\" style=\\"padding-bottom: 20px;\\">
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">If you have any further questions, please contact our support.</div><a class=\\"footer_p2\\" href=\\"mailto:support@gradido.net\\" style=\\"color: #383838; font-weight: bold;\\">support@gradido.net</a>
|
||||
<div> <img class=\\"image\\" alt=\\"Gradido Logo\\" src=\\"https://gdd.gradido.net/img/brand/green.png\\" style=\\"width: 200px; margin-top: 30px; margin-bottom: 30px;\\" width=\\"200\\"></div>
|
||||
<div><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/impressum/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Impressum</a></div><br><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/datenschutz/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Privacy Policy</a>
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
<div class=\"w-container footer_01\">
|
||||
<div class=\"socialmedia\" style=\"display: flex; margin-top: 40px; max-width: 600px;\"><a class=\"slink\" target=\"_blank\" href=\"https://www.facebook.com/groups/Gradido/\" style=\"width: 150px;\"><img class=\"bi-facebook\" alt=\"facebook\" loading=\"lazy\" src=\"cid:facebookicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://t.me/GradidoGruppe\" style=\"width: 150px;\"><img class=\"bi-telegram\" alt=\"Telegram\" loading=\"lazy\" src=\"cid:telegramicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://twitter.com/gradido\" style=\"width: 150px;\"><img class=\"bi-twitter\" alt=\"Twitter\" loading=\"lazy\" src=\"cid:twittericon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://www.youtube.com/c/GradidoNet\" style=\"width: 150px;\"><img class=\"bi-youtube\" alt=\"youtube\" loading=\"lazy\" src=\"cid:youtubeicon\"></a></div>
|
||||
<div class=\"line\" style=\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\"></div>
|
||||
<div class=\"footer\" style=\"padding-bottom: 20px;\">
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">If you have any further questions, please contact our support.</div><a class=\"footer_p2\" href=\"mailto:support@gradido.net\" style=\"color: #383838; font-weight: bold;\">support@gradido.net</a>
|
||||
<div> <img class=\"image\" alt=\"Gradido Logo\" src=\"https://gdd.gradido.net/img/brand/green.png\" style=\"width: 200px; margin-top: 30px; margin-bottom: 30px;\" width=\"200\"></div>
|
||||
<div><a class=\"terms_of_use\" href=\"https://gradido.net/de/impressum/\" target=\"_blank\" style=\"color: #9ca0a8;\">Impressum</a></div><br><a class=\"terms_of_use\" href=\"https://gradido.net/de/datenschutz/\" target=\"_blank\" style=\"color: #9ca0a8;\">Privacy Policy</a>
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@ -352,12 +352,12 @@ exports[`sendEmailVariants sendAccountMultiRegistrationEmail calls "sendEmailTra
|
||||
|
||||
exports[`sendEmailVariants sendAddedContributionMessageEmail result has the correct html as snapshot 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\\"en\\">
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta content=\\"multipart/html; charset=UTF-8\\" http-equiv=\\"content-type\\">
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1\\">
|
||||
<meta content=\"multipart/html; charset=UTF-8\" http-equiv=\"content-type\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<style>
|
||||
.wf-force-outline-none[tabindex=\\"-1\\"]:focus {
|
||||
.wf-force-outline-none[tabindex=\"-1\"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
@ -483,39 +483,39 @@ exports[`sendEmailVariants sendAddedContributionMessageEmail result has the corr
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style=\\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\\">
|
||||
<div class=\\"container\\" style=\\"max-width: 680px; margin: 0 auto; display: block;\\">
|
||||
<body style=\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\">
|
||||
<div class=\"container\" style=\"max-width: 680px; margin: 0 auto; display: block;\">
|
||||
<header>
|
||||
<div class=\\"head\\"><img class=\\"head-logo\\" alt=\\"Gradido Logo\\" loading=\\"lazy\\" src=\\"cid:gradidoheader\\" style=\\"width: 100%; height: auto;\\"></div>
|
||||
<div class=\"head\"><img class=\"head-logo\" alt=\"Gradido Logo\" loading=\"lazy\" src=\"cid:gradidoheader\" style=\"width: 100%; height: auto;\"></div>
|
||||
</header>
|
||||
<div class=\\"wrapper\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Message about your common good contribution</h2>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"wrapper\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Message about your common good contribution</h2>
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Hello Peter Lustig,</p>
|
||||
<p>You have received a message from Bibi Bloxberg regarding your common good contribution “My contribution.”.</p>
|
||||
</div>
|
||||
<div class=\\"content\\" style=\\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Read and reply to message</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">
|
||||
<div class=\"content\" style=\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Read and reply to message</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">
|
||||
<p>„My message.“</p>
|
||||
<p>To reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.</p>
|
||||
</div><a class=\\"button-3\\" href=\\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\\">To account</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Please do not reply to this email.</div>
|
||||
</div><a class=\"button-3\" href=\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\">To account</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Please do not reply to this email.</div>
|
||||
</div>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Kind regards,<br>your Gradido team
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class=\\"w-container footer_01\\">
|
||||
<div class=\\"socialmedia\\" style=\\"display: flex; margin-top: 40px; max-width: 600px;\\"><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.facebook.com/groups/Gradido/\\" style=\\"width: 150px;\\"><img class=\\"bi-facebook\\" alt=\\"facebook\\" loading=\\"lazy\\" src=\\"cid:facebookicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://t.me/GradidoGruppe\\" style=\\"width: 150px;\\"><img class=\\"bi-telegram\\" alt=\\"Telegram\\" loading=\\"lazy\\" src=\\"cid:telegramicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://twitter.com/gradido\\" style=\\"width: 150px;\\"><img class=\\"bi-twitter\\" alt=\\"Twitter\\" loading=\\"lazy\\" src=\\"cid:twittericon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.youtube.com/c/GradidoNet\\" style=\\"width: 150px;\\"><img class=\\"bi-youtube\\" alt=\\"youtube\\" loading=\\"lazy\\" src=\\"cid:youtubeicon\\"></a></div>
|
||||
<div class=\\"line\\" style=\\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\\"></div>
|
||||
<div class=\\"footer\\" style=\\"padding-bottom: 20px;\\">
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">If you have any further questions, please contact our support.</div><a class=\\"footer_p2\\" href=\\"mailto:support@gradido.net\\" style=\\"color: #383838; font-weight: bold;\\">support@gradido.net</a>
|
||||
<div> <img class=\\"image\\" alt=\\"Gradido Logo\\" src=\\"https://gdd.gradido.net/img/brand/green.png\\" style=\\"width: 200px; margin-top: 30px; margin-bottom: 30px;\\" width=\\"200\\"></div>
|
||||
<div><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/impressum/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Impressum</a></div><br><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/datenschutz/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Privacy Policy</a>
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
<div class=\"w-container footer_01\">
|
||||
<div class=\"socialmedia\" style=\"display: flex; margin-top: 40px; max-width: 600px;\"><a class=\"slink\" target=\"_blank\" href=\"https://www.facebook.com/groups/Gradido/\" style=\"width: 150px;\"><img class=\"bi-facebook\" alt=\"facebook\" loading=\"lazy\" src=\"cid:facebookicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://t.me/GradidoGruppe\" style=\"width: 150px;\"><img class=\"bi-telegram\" alt=\"Telegram\" loading=\"lazy\" src=\"cid:telegramicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://twitter.com/gradido\" style=\"width: 150px;\"><img class=\"bi-twitter\" alt=\"Twitter\" loading=\"lazy\" src=\"cid:twittericon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://www.youtube.com/c/GradidoNet\" style=\"width: 150px;\"><img class=\"bi-youtube\" alt=\"youtube\" loading=\"lazy\" src=\"cid:youtubeicon\"></a></div>
|
||||
<div class=\"line\" style=\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\"></div>
|
||||
<div class=\"footer\" style=\"padding-bottom: 20px;\">
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">If you have any further questions, please contact our support.</div><a class=\"footer_p2\" href=\"mailto:support@gradido.net\" style=\"color: #383838; font-weight: bold;\">support@gradido.net</a>
|
||||
<div> <img class=\"image\" alt=\"Gradido Logo\" src=\"https://gdd.gradido.net/img/brand/green.png\" style=\"width: 200px; margin-top: 30px; margin-bottom: 30px;\" width=\"200\"></div>
|
||||
<div><a class=\"terms_of_use\" href=\"https://gradido.net/de/impressum/\" target=\"_blank\" style=\"color: #9ca0a8;\">Impressum</a></div><br><a class=\"terms_of_use\" href=\"https://gradido.net/de/datenschutz/\" target=\"_blank\" style=\"color: #9ca0a8;\">Privacy Policy</a>
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@ -526,12 +526,12 @@ exports[`sendEmailVariants sendAddedContributionMessageEmail result has the corr
|
||||
|
||||
exports[`sendEmailVariants sendContributionChangedByModeratorEmail result has the correct html as snapshot 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\\"en\\">
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta content=\\"multipart/html; charset=UTF-8\\" http-equiv=\\"content-type\\">
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1\\">
|
||||
<meta content=\"multipart/html; charset=UTF-8\" http-equiv=\"content-type\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<style>
|
||||
.wf-force-outline-none[tabindex=\\"-1\\"]:focus {
|
||||
.wf-force-outline-none[tabindex=\"-1\"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
@ -657,37 +657,37 @@ exports[`sendEmailVariants sendContributionChangedByModeratorEmail result has th
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style=\\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\\">
|
||||
<div class=\\"container\\" style=\\"max-width: 680px; margin: 0 auto; display: block;\\">
|
||||
<body style=\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\">
|
||||
<div class=\"container\" style=\"max-width: 680px; margin: 0 auto; display: block;\">
|
||||
<header>
|
||||
<div class=\\"head\\"><img class=\\"head-logo\\" alt=\\"Gradido Logo\\" loading=\\"lazy\\" src=\\"cid:gradidoheader\\" style=\\"width: 100%; height: auto;\\"></div>
|
||||
<div class=\"head\"><img class=\"head-logo\" alt=\"Gradido Logo\" loading=\"lazy\" src=\"cid:gradidoheader\" style=\"width: 100%; height: auto;\"></div>
|
||||
</header>
|
||||
<div class=\\"wrapper\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Your common good contribution has been changed</h2>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"wrapper\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Your common good contribution has been changed</h2>
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Hello Peter Lustig,</p>
|
||||
<p>your common good contribution 'My contribution.' has just been changed by Bibi Bloxberg and now reads as 'This is a better contribution memo.'</p>
|
||||
</div>
|
||||
<div class=\\"content\\" style=\\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Contribution details</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.</div><a class=\\"button-3\\" href=\\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\\">To account</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Or copy the link into your browser window.</div><a class=\\"clink\\" href=\\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\\" style=\\"line-break: anywhere; margin-bottom: 40px;\\">https://gradido.net/contributions/own-contributions/1#contributionListItem-1</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Please do not reply to this email.</div>
|
||||
<div class=\"content\" style=\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Contribution details</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.</div><a class=\"button-3\" href=\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\">To account</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Or copy the link into your browser window.</div><a class=\"clink\" href=\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\" style=\"line-break: anywhere; margin-bottom: 40px;\">https://gradido.net/contributions/own-contributions/1#contributionListItem-1</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Please do not reply to this email.</div>
|
||||
</div>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Kind regards,<br>your Gradido team
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class=\\"w-container footer_01\\">
|
||||
<div class=\\"socialmedia\\" style=\\"display: flex; margin-top: 40px; max-width: 600px;\\"><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.facebook.com/groups/Gradido/\\" style=\\"width: 150px;\\"><img class=\\"bi-facebook\\" alt=\\"facebook\\" loading=\\"lazy\\" src=\\"cid:facebookicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://t.me/GradidoGruppe\\" style=\\"width: 150px;\\"><img class=\\"bi-telegram\\" alt=\\"Telegram\\" loading=\\"lazy\\" src=\\"cid:telegramicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://twitter.com/gradido\\" style=\\"width: 150px;\\"><img class=\\"bi-twitter\\" alt=\\"Twitter\\" loading=\\"lazy\\" src=\\"cid:twittericon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.youtube.com/c/GradidoNet\\" style=\\"width: 150px;\\"><img class=\\"bi-youtube\\" alt=\\"youtube\\" loading=\\"lazy\\" src=\\"cid:youtubeicon\\"></a></div>
|
||||
<div class=\\"line\\" style=\\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\\"></div>
|
||||
<div class=\\"footer\\" style=\\"padding-bottom: 20px;\\">
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">If you have any further questions, please contact our support.</div><a class=\\"footer_p2\\" href=\\"mailto:support@gradido.net\\" style=\\"color: #383838; font-weight: bold;\\">support@gradido.net</a>
|
||||
<div> <img class=\\"image\\" alt=\\"Gradido Logo\\" src=\\"https://gdd.gradido.net/img/brand/green.png\\" style=\\"width: 200px; margin-top: 30px; margin-bottom: 30px;\\" width=\\"200\\"></div>
|
||||
<div><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/impressum/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Impressum</a></div><br><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/datenschutz/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Privacy Policy</a>
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
<div class=\"w-container footer_01\">
|
||||
<div class=\"socialmedia\" style=\"display: flex; margin-top: 40px; max-width: 600px;\"><a class=\"slink\" target=\"_blank\" href=\"https://www.facebook.com/groups/Gradido/\" style=\"width: 150px;\"><img class=\"bi-facebook\" alt=\"facebook\" loading=\"lazy\" src=\"cid:facebookicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://t.me/GradidoGruppe\" style=\"width: 150px;\"><img class=\"bi-telegram\" alt=\"Telegram\" loading=\"lazy\" src=\"cid:telegramicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://twitter.com/gradido\" style=\"width: 150px;\"><img class=\"bi-twitter\" alt=\"Twitter\" loading=\"lazy\" src=\"cid:twittericon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://www.youtube.com/c/GradidoNet\" style=\"width: 150px;\"><img class=\"bi-youtube\" alt=\"youtube\" loading=\"lazy\" src=\"cid:youtubeicon\"></a></div>
|
||||
<div class=\"line\" style=\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\"></div>
|
||||
<div class=\"footer\" style=\"padding-bottom: 20px;\">
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">If you have any further questions, please contact our support.</div><a class=\"footer_p2\" href=\"mailto:support@gradido.net\" style=\"color: #383838; font-weight: bold;\">support@gradido.net</a>
|
||||
<div> <img class=\"image\" alt=\"Gradido Logo\" src=\"https://gdd.gradido.net/img/brand/green.png\" style=\"width: 200px; margin-top: 30px; margin-bottom: 30px;\" width=\"200\"></div>
|
||||
<div><a class=\"terms_of_use\" href=\"https://gradido.net/de/impressum/\" target=\"_blank\" style=\"color: #9ca0a8;\">Impressum</a></div><br><a class=\"terms_of_use\" href=\"https://gradido.net/de/datenschutz/\" target=\"_blank\" style=\"color: #9ca0a8;\">Privacy Policy</a>
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@ -698,12 +698,12 @@ exports[`sendEmailVariants sendContributionChangedByModeratorEmail result has th
|
||||
|
||||
exports[`sendEmailVariants sendContributionConfirmedEmail result has the correct html as snapshot 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\\"en\\">
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta content=\\"multipart/html; charset=UTF-8\\" http-equiv=\\"content-type\\">
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1\\">
|
||||
<meta content=\"multipart/html; charset=UTF-8\" http-equiv=\"content-type\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<style>
|
||||
.wf-force-outline-none[tabindex=\\"-1\\"]:focus {
|
||||
.wf-force-outline-none[tabindex=\"-1\"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
@ -829,37 +829,37 @@ exports[`sendEmailVariants sendContributionConfirmedEmail result has the correct
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style=\\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\\">
|
||||
<div class=\\"container\\" style=\\"max-width: 680px; margin: 0 auto; display: block;\\">
|
||||
<body style=\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\">
|
||||
<div class=\"container\" style=\"max-width: 680px; margin: 0 auto; display: block;\">
|
||||
<header>
|
||||
<div class=\\"head\\"><img class=\\"head-logo\\" alt=\\"Gradido Logo\\" loading=\\"lazy\\" src=\\"cid:gradidoheader\\" style=\\"width: 100%; height: auto;\\"></div>
|
||||
<div class=\"head\"><img class=\"head-logo\" alt=\"Gradido Logo\" loading=\"lazy\" src=\"cid:gradidoheader\" style=\"width: 100%; height: auto;\"></div>
|
||||
</header>
|
||||
<div class=\\"wrapper\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Your contribution to the common good was confirmed</h2>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"wrapper\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Your contribution to the common good was confirmed</h2>
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Hello Peter Lustig,</p>
|
||||
<p>Your common good contribution “My contribution.” has just been approved by Bibi Bloxberg. Your Gradido account has been credited with 23.54 GDD.</p>
|
||||
</div>
|
||||
<div class=\\"content\\" style=\\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Contribution details</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.</div><a class=\\"button-3\\" href=\\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\\">To account</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Or copy the link into your browser window.</div><a class=\\"clink\\" href=\\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\\" style=\\"line-break: anywhere; margin-bottom: 40px;\\">https://gradido.net/contributions/own-contributions/1#contributionListItem-1</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Please do not reply to this email.</div>
|
||||
<div class=\"content\" style=\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Contribution details</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.</div><a class=\"button-3\" href=\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\">To account</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Or copy the link into your browser window.</div><a class=\"clink\" href=\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\" style=\"line-break: anywhere; margin-bottom: 40px;\">https://gradido.net/contributions/own-contributions/1#contributionListItem-1</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Please do not reply to this email.</div>
|
||||
</div>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Kind regards,<br>your Gradido team
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class=\\"w-container footer_01\\">
|
||||
<div class=\\"socialmedia\\" style=\\"display: flex; margin-top: 40px; max-width: 600px;\\"><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.facebook.com/groups/Gradido/\\" style=\\"width: 150px;\\"><img class=\\"bi-facebook\\" alt=\\"facebook\\" loading=\\"lazy\\" src=\\"cid:facebookicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://t.me/GradidoGruppe\\" style=\\"width: 150px;\\"><img class=\\"bi-telegram\\" alt=\\"Telegram\\" loading=\\"lazy\\" src=\\"cid:telegramicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://twitter.com/gradido\\" style=\\"width: 150px;\\"><img class=\\"bi-twitter\\" alt=\\"Twitter\\" loading=\\"lazy\\" src=\\"cid:twittericon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.youtube.com/c/GradidoNet\\" style=\\"width: 150px;\\"><img class=\\"bi-youtube\\" alt=\\"youtube\\" loading=\\"lazy\\" src=\\"cid:youtubeicon\\"></a></div>
|
||||
<div class=\\"line\\" style=\\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\\"></div>
|
||||
<div class=\\"footer\\" style=\\"padding-bottom: 20px;\\">
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">If you have any further questions, please contact our support.</div><a class=\\"footer_p2\\" href=\\"mailto:support@gradido.net\\" style=\\"color: #383838; font-weight: bold;\\">support@gradido.net</a>
|
||||
<div> <img class=\\"image\\" alt=\\"Gradido Logo\\" src=\\"https://gdd.gradido.net/img/brand/green.png\\" style=\\"width: 200px; margin-top: 30px; margin-bottom: 30px;\\" width=\\"200\\"></div>
|
||||
<div><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/impressum/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Impressum</a></div><br><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/datenschutz/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Privacy Policy</a>
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
<div class=\"w-container footer_01\">
|
||||
<div class=\"socialmedia\" style=\"display: flex; margin-top: 40px; max-width: 600px;\"><a class=\"slink\" target=\"_blank\" href=\"https://www.facebook.com/groups/Gradido/\" style=\"width: 150px;\"><img class=\"bi-facebook\" alt=\"facebook\" loading=\"lazy\" src=\"cid:facebookicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://t.me/GradidoGruppe\" style=\"width: 150px;\"><img class=\"bi-telegram\" alt=\"Telegram\" loading=\"lazy\" src=\"cid:telegramicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://twitter.com/gradido\" style=\"width: 150px;\"><img class=\"bi-twitter\" alt=\"Twitter\" loading=\"lazy\" src=\"cid:twittericon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://www.youtube.com/c/GradidoNet\" style=\"width: 150px;\"><img class=\"bi-youtube\" alt=\"youtube\" loading=\"lazy\" src=\"cid:youtubeicon\"></a></div>
|
||||
<div class=\"line\" style=\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\"></div>
|
||||
<div class=\"footer\" style=\"padding-bottom: 20px;\">
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">If you have any further questions, please contact our support.</div><a class=\"footer_p2\" href=\"mailto:support@gradido.net\" style=\"color: #383838; font-weight: bold;\">support@gradido.net</a>
|
||||
<div> <img class=\"image\" alt=\"Gradido Logo\" src=\"https://gdd.gradido.net/img/brand/green.png\" style=\"width: 200px; margin-top: 30px; margin-bottom: 30px;\" width=\"200\"></div>
|
||||
<div><a class=\"terms_of_use\" href=\"https://gradido.net/de/impressum/\" target=\"_blank\" style=\"color: #9ca0a8;\">Impressum</a></div><br><a class=\"terms_of_use\" href=\"https://gradido.net/de/datenschutz/\" target=\"_blank\" style=\"color: #9ca0a8;\">Privacy Policy</a>
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@ -870,12 +870,12 @@ exports[`sendEmailVariants sendContributionConfirmedEmail result has the correct
|
||||
|
||||
exports[`sendEmailVariants sendContributionDeletedEmail result has the correct html as snapshot 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\\"en\\">
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta content=\\"multipart/html; charset=UTF-8\\" http-equiv=\\"content-type\\">
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1\\">
|
||||
<meta content=\"multipart/html; charset=UTF-8\" http-equiv=\"content-type\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<style>
|
||||
.wf-force-outline-none[tabindex=\\"-1\\"]:focus {
|
||||
.wf-force-outline-none[tabindex=\"-1\"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
@ -1001,37 +1001,37 @@ exports[`sendEmailVariants sendContributionDeletedEmail result has the correct h
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style=\\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\\">
|
||||
<div class=\\"container\\" style=\\"max-width: 680px; margin: 0 auto; display: block;\\">
|
||||
<body style=\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\">
|
||||
<div class=\"container\" style=\"max-width: 680px; margin: 0 auto; display: block;\">
|
||||
<header>
|
||||
<div class=\\"head\\"><img class=\\"head-logo\\" alt=\\"Gradido Logo\\" loading=\\"lazy\\" src=\\"cid:gradidoheader\\" style=\\"width: 100%; height: auto;\\"></div>
|
||||
<div class=\"head\"><img class=\"head-logo\" alt=\"Gradido Logo\" loading=\"lazy\" src=\"cid:gradidoheader\" style=\"width: 100%; height: auto;\"></div>
|
||||
</header>
|
||||
<div class=\\"wrapper\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Your common good contribution was deleted</h2>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"wrapper\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Your common good contribution was deleted</h2>
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Hello Peter Lustig,</p>
|
||||
<p>Your common good contribution “My contribution.” was deleted by Bibi Bloxberg.</p>
|
||||
</div>
|
||||
<div class=\\"content\\" style=\\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Contribution details</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.</div><a class=\\"button-3\\" href=\\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\\">To account</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Or copy the link into your browser window.</div><a class=\\"clink\\" href=\\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\\" style=\\"line-break: anywhere; margin-bottom: 40px;\\">https://gradido.net/contributions/own-contributions/1#contributionListItem-1</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Please do not reply to this email.</div>
|
||||
<div class=\"content\" style=\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Contribution details</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.</div><a class=\"button-3\" href=\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\">To account</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Or copy the link into your browser window.</div><a class=\"clink\" href=\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\" style=\"line-break: anywhere; margin-bottom: 40px;\">https://gradido.net/contributions/own-contributions/1#contributionListItem-1</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Please do not reply to this email.</div>
|
||||
</div>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Kind regards,<br>your Gradido team
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class=\\"w-container footer_01\\">
|
||||
<div class=\\"socialmedia\\" style=\\"display: flex; margin-top: 40px; max-width: 600px;\\"><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.facebook.com/groups/Gradido/\\" style=\\"width: 150px;\\"><img class=\\"bi-facebook\\" alt=\\"facebook\\" loading=\\"lazy\\" src=\\"cid:facebookicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://t.me/GradidoGruppe\\" style=\\"width: 150px;\\"><img class=\\"bi-telegram\\" alt=\\"Telegram\\" loading=\\"lazy\\" src=\\"cid:telegramicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://twitter.com/gradido\\" style=\\"width: 150px;\\"><img class=\\"bi-twitter\\" alt=\\"Twitter\\" loading=\\"lazy\\" src=\\"cid:twittericon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.youtube.com/c/GradidoNet\\" style=\\"width: 150px;\\"><img class=\\"bi-youtube\\" alt=\\"youtube\\" loading=\\"lazy\\" src=\\"cid:youtubeicon\\"></a></div>
|
||||
<div class=\\"line\\" style=\\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\\"></div>
|
||||
<div class=\\"footer\\" style=\\"padding-bottom: 20px;\\">
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">If you have any further questions, please contact our support.</div><a class=\\"footer_p2\\" href=\\"mailto:support@gradido.net\\" style=\\"color: #383838; font-weight: bold;\\">support@gradido.net</a>
|
||||
<div> <img class=\\"image\\" alt=\\"Gradido Logo\\" src=\\"https://gdd.gradido.net/img/brand/green.png\\" style=\\"width: 200px; margin-top: 30px; margin-bottom: 30px;\\" width=\\"200\\"></div>
|
||||
<div><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/impressum/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Impressum</a></div><br><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/datenschutz/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Privacy Policy</a>
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
<div class=\"w-container footer_01\">
|
||||
<div class=\"socialmedia\" style=\"display: flex; margin-top: 40px; max-width: 600px;\"><a class=\"slink\" target=\"_blank\" href=\"https://www.facebook.com/groups/Gradido/\" style=\"width: 150px;\"><img class=\"bi-facebook\" alt=\"facebook\" loading=\"lazy\" src=\"cid:facebookicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://t.me/GradidoGruppe\" style=\"width: 150px;\"><img class=\"bi-telegram\" alt=\"Telegram\" loading=\"lazy\" src=\"cid:telegramicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://twitter.com/gradido\" style=\"width: 150px;\"><img class=\"bi-twitter\" alt=\"Twitter\" loading=\"lazy\" src=\"cid:twittericon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://www.youtube.com/c/GradidoNet\" style=\"width: 150px;\"><img class=\"bi-youtube\" alt=\"youtube\" loading=\"lazy\" src=\"cid:youtubeicon\"></a></div>
|
||||
<div class=\"line\" style=\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\"></div>
|
||||
<div class=\"footer\" style=\"padding-bottom: 20px;\">
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">If you have any further questions, please contact our support.</div><a class=\"footer_p2\" href=\"mailto:support@gradido.net\" style=\"color: #383838; font-weight: bold;\">support@gradido.net</a>
|
||||
<div> <img class=\"image\" alt=\"Gradido Logo\" src=\"https://gdd.gradido.net/img/brand/green.png\" style=\"width: 200px; margin-top: 30px; margin-bottom: 30px;\" width=\"200\"></div>
|
||||
<div><a class=\"terms_of_use\" href=\"https://gradido.net/de/impressum/\" target=\"_blank\" style=\"color: #9ca0a8;\">Impressum</a></div><br><a class=\"terms_of_use\" href=\"https://gradido.net/de/datenschutz/\" target=\"_blank\" style=\"color: #9ca0a8;\">Privacy Policy</a>
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@ -1042,12 +1042,12 @@ exports[`sendEmailVariants sendContributionDeletedEmail result has the correct h
|
||||
|
||||
exports[`sendEmailVariants sendContributionDeniedEmail result has the correct html as snapshot 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\\"en\\">
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta content=\\"multipart/html; charset=UTF-8\\" http-equiv=\\"content-type\\">
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1\\">
|
||||
<meta content=\"multipart/html; charset=UTF-8\" http-equiv=\"content-type\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<style>
|
||||
.wf-force-outline-none[tabindex=\\"-1\\"]:focus {
|
||||
.wf-force-outline-none[tabindex=\"-1\"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
@ -1173,37 +1173,37 @@ exports[`sendEmailVariants sendContributionDeniedEmail result has the correct ht
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style=\\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\\">
|
||||
<div class=\\"container\\" style=\\"max-width: 680px; margin: 0 auto; display: block;\\">
|
||||
<body style=\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\">
|
||||
<div class=\"container\" style=\"max-width: 680px; margin: 0 auto; display: block;\">
|
||||
<header>
|
||||
<div class=\\"head\\"><img class=\\"head-logo\\" alt=\\"Gradido Logo\\" loading=\\"lazy\\" src=\\"cid:gradidoheader\\" style=\\"width: 100%; height: auto;\\"></div>
|
||||
<div class=\"head\"><img class=\"head-logo\" alt=\"Gradido Logo\" loading=\"lazy\" src=\"cid:gradidoheader\" style=\"width: 100%; height: auto;\"></div>
|
||||
</header>
|
||||
<div class=\\"wrapper\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Your common good contribution was rejected</h2>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"wrapper\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Your common good contribution was rejected</h2>
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Hello Peter Lustig,</p>
|
||||
<p>Your common good contribution “My contribution.” was rejected by Bibi Bloxberg.</p>
|
||||
</div>
|
||||
<div class=\\"content\\" style=\\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Contribution details</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.</div><a class=\\"button-3\\" href=\\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\\">To account</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Or copy the link into your browser window.</div><a class=\\"clink\\" href=\\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\\" style=\\"line-break: anywhere; margin-bottom: 40px;\\">https://gradido.net/contributions/own-contributions/1#contributionListItem-1</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Please do not reply to this email.</div>
|
||||
<div class=\"content\" style=\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Contribution details</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.</div><a class=\"button-3\" href=\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\">To account</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Or copy the link into your browser window.</div><a class=\"clink\" href=\"https://gradido.net/contributions/own-contributions/1#contributionListItem-1\" style=\"line-break: anywhere; margin-bottom: 40px;\">https://gradido.net/contributions/own-contributions/1#contributionListItem-1</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Please do not reply to this email.</div>
|
||||
</div>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Kind regards,<br>your Gradido team
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class=\\"w-container footer_01\\">
|
||||
<div class=\\"socialmedia\\" style=\\"display: flex; margin-top: 40px; max-width: 600px;\\"><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.facebook.com/groups/Gradido/\\" style=\\"width: 150px;\\"><img class=\\"bi-facebook\\" alt=\\"facebook\\" loading=\\"lazy\\" src=\\"cid:facebookicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://t.me/GradidoGruppe\\" style=\\"width: 150px;\\"><img class=\\"bi-telegram\\" alt=\\"Telegram\\" loading=\\"lazy\\" src=\\"cid:telegramicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://twitter.com/gradido\\" style=\\"width: 150px;\\"><img class=\\"bi-twitter\\" alt=\\"Twitter\\" loading=\\"lazy\\" src=\\"cid:twittericon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.youtube.com/c/GradidoNet\\" style=\\"width: 150px;\\"><img class=\\"bi-youtube\\" alt=\\"youtube\\" loading=\\"lazy\\" src=\\"cid:youtubeicon\\"></a></div>
|
||||
<div class=\\"line\\" style=\\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\\"></div>
|
||||
<div class=\\"footer\\" style=\\"padding-bottom: 20px;\\">
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">If you have any further questions, please contact our support.</div><a class=\\"footer_p2\\" href=\\"mailto:support@gradido.net\\" style=\\"color: #383838; font-weight: bold;\\">support@gradido.net</a>
|
||||
<div> <img class=\\"image\\" alt=\\"Gradido Logo\\" src=\\"https://gdd.gradido.net/img/brand/green.png\\" style=\\"width: 200px; margin-top: 30px; margin-bottom: 30px;\\" width=\\"200\\"></div>
|
||||
<div><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/impressum/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Impressum</a></div><br><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/datenschutz/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Privacy Policy</a>
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
<div class=\"w-container footer_01\">
|
||||
<div class=\"socialmedia\" style=\"display: flex; margin-top: 40px; max-width: 600px;\"><a class=\"slink\" target=\"_blank\" href=\"https://www.facebook.com/groups/Gradido/\" style=\"width: 150px;\"><img class=\"bi-facebook\" alt=\"facebook\" loading=\"lazy\" src=\"cid:facebookicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://t.me/GradidoGruppe\" style=\"width: 150px;\"><img class=\"bi-telegram\" alt=\"Telegram\" loading=\"lazy\" src=\"cid:telegramicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://twitter.com/gradido\" style=\"width: 150px;\"><img class=\"bi-twitter\" alt=\"Twitter\" loading=\"lazy\" src=\"cid:twittericon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://www.youtube.com/c/GradidoNet\" style=\"width: 150px;\"><img class=\"bi-youtube\" alt=\"youtube\" loading=\"lazy\" src=\"cid:youtubeicon\"></a></div>
|
||||
<div class=\"line\" style=\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\"></div>
|
||||
<div class=\"footer\" style=\"padding-bottom: 20px;\">
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">If you have any further questions, please contact our support.</div><a class=\"footer_p2\" href=\"mailto:support@gradido.net\" style=\"color: #383838; font-weight: bold;\">support@gradido.net</a>
|
||||
<div> <img class=\"image\" alt=\"Gradido Logo\" src=\"https://gdd.gradido.net/img/brand/green.png\" style=\"width: 200px; margin-top: 30px; margin-bottom: 30px;\" width=\"200\"></div>
|
||||
<div><a class=\"terms_of_use\" href=\"https://gradido.net/de/impressum/\" target=\"_blank\" style=\"color: #9ca0a8;\">Impressum</a></div><br><a class=\"terms_of_use\" href=\"https://gradido.net/de/datenschutz/\" target=\"_blank\" style=\"color: #9ca0a8;\">Privacy Policy</a>
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@ -1214,12 +1214,12 @@ exports[`sendEmailVariants sendContributionDeniedEmail result has the correct ht
|
||||
|
||||
exports[`sendEmailVariants sendResetPasswordEmail result has the correct html as snapshot 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\\"en\\">
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta content=\\"multipart/html; charset=UTF-8\\" http-equiv=\\"content-type\\">
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1\\">
|
||||
<meta content=\"multipart/html; charset=UTF-8\" http-equiv=\"content-type\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<style>
|
||||
.wf-force-outline-none[tabindex=\\"-1\\"]:focus {
|
||||
.wf-force-outline-none[tabindex=\"-1\"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
@ -1345,41 +1345,41 @@ exports[`sendEmailVariants sendResetPasswordEmail result has the correct html as
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style=\\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\\">
|
||||
<div class=\\"container\\" style=\\"max-width: 680px; margin: 0 auto; display: block;\\">
|
||||
<body style=\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\">
|
||||
<div class=\"container\" style=\"max-width: 680px; margin: 0 auto; display: block;\">
|
||||
<header>
|
||||
<div class=\\"head\\"><img class=\\"head-logo\\" alt=\\"Gradido Logo\\" loading=\\"lazy\\" src=\\"cid:gradidoheader\\" style=\\"width: 100%; height: auto;\\"></div>
|
||||
<div class=\"head\"><img class=\"head-logo\" alt=\"Gradido Logo\" loading=\"lazy\" src=\"cid:gradidoheader\" style=\"width: 100%; height: auto;\"></div>
|
||||
</header>
|
||||
<div class=\\"wrapper\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Reset password</h2>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"wrapper\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Reset password</h2>
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Hello Peter Lustig,</p>
|
||||
<p>You, or someone else, requested a password reset for this account.</p>
|
||||
</div>
|
||||
<div class=\\"content\\" style=\\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Reset password</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">If it was you, please click here.</div><a class=\\"button-3\\" href=\\"http://localhost/reset-password/3762660021544901417\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\\">reset</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Or copy the link into your browser window.</div><a class=\\"clink\\" href=\\"http://localhost/reset-password/3762660021544901417\\" style=\\"line-break: anywhere; margin-bottom: 40px;\\">http://localhost/reset-password/3762660021544901417</a>
|
||||
<div class=\"content\" style=\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Reset password</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">If it was you, please click here.</div><a class=\"button-3\" href=\"http://localhost/reset-password/3762660021544901417\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\">reset</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Or copy the link into your browser window.</div><a class=\"clink\" href=\"http://localhost/reset-password/3762660021544901417\" style=\"line-break: anywhere; margin-bottom: 40px;\">http://localhost/reset-password/3762660021544901417</a>
|
||||
<requestnewlink>
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Request new valid link</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">The link has a validity of 23 hours and 30 minutes.
|
||||
If the validity of the link has already expired, you can have a new link sent to you here.</div><a class=\\"button-4\\" href=\\"http://localhost/forgot-password\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%; background-image: radial-gradient(circle farthest-corner at 0% 0%, #616161, #c2c2c2);\\">New link</a>
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Request new valid link</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">The link has a validity of 23 hours and 30 minutes.
|
||||
If the validity of the link has already expired, you can have a new link sent to you here.</div><a class=\"button-4\" href=\"http://localhost/forgot-password\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%; background-image: radial-gradient(circle farthest-corner at 0% 0%, #616161, #c2c2c2);\">New link</a>
|
||||
</requestnewlink>
|
||||
</div>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Kind regards,<br>your Gradido team
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class=\\"w-container footer_01\\">
|
||||
<div class=\\"socialmedia\\" style=\\"display: flex; margin-top: 40px; max-width: 600px;\\"><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.facebook.com/groups/Gradido/\\" style=\\"width: 150px;\\"><img class=\\"bi-facebook\\" alt=\\"facebook\\" loading=\\"lazy\\" src=\\"cid:facebookicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://t.me/GradidoGruppe\\" style=\\"width: 150px;\\"><img class=\\"bi-telegram\\" alt=\\"Telegram\\" loading=\\"lazy\\" src=\\"cid:telegramicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://twitter.com/gradido\\" style=\\"width: 150px;\\"><img class=\\"bi-twitter\\" alt=\\"Twitter\\" loading=\\"lazy\\" src=\\"cid:twittericon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.youtube.com/c/GradidoNet\\" style=\\"width: 150px;\\"><img class=\\"bi-youtube\\" alt=\\"youtube\\" loading=\\"lazy\\" src=\\"cid:youtubeicon\\"></a></div>
|
||||
<div class=\\"line\\" style=\\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\\"></div>
|
||||
<div class=\\"footer\\" style=\\"padding-bottom: 20px;\\">
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">If you have any further questions, please contact our support.</div><a class=\\"footer_p2\\" href=\\"mailto:support@gradido.net\\" style=\\"color: #383838; font-weight: bold;\\">support@gradido.net</a>
|
||||
<div> <img class=\\"image\\" alt=\\"Gradido Logo\\" src=\\"https://gdd.gradido.net/img/brand/green.png\\" style=\\"width: 200px; margin-top: 30px; margin-bottom: 30px;\\" width=\\"200\\"></div>
|
||||
<div><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/impressum/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Impressum</a></div><br><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/datenschutz/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Privacy Policy</a>
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
<div class=\"w-container footer_01\">
|
||||
<div class=\"socialmedia\" style=\"display: flex; margin-top: 40px; max-width: 600px;\"><a class=\"slink\" target=\"_blank\" href=\"https://www.facebook.com/groups/Gradido/\" style=\"width: 150px;\"><img class=\"bi-facebook\" alt=\"facebook\" loading=\"lazy\" src=\"cid:facebookicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://t.me/GradidoGruppe\" style=\"width: 150px;\"><img class=\"bi-telegram\" alt=\"Telegram\" loading=\"lazy\" src=\"cid:telegramicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://twitter.com/gradido\" style=\"width: 150px;\"><img class=\"bi-twitter\" alt=\"Twitter\" loading=\"lazy\" src=\"cid:twittericon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://www.youtube.com/c/GradidoNet\" style=\"width: 150px;\"><img class=\"bi-youtube\" alt=\"youtube\" loading=\"lazy\" src=\"cid:youtubeicon\"></a></div>
|
||||
<div class=\"line\" style=\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\"></div>
|
||||
<div class=\"footer\" style=\"padding-bottom: 20px;\">
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">If you have any further questions, please contact our support.</div><a class=\"footer_p2\" href=\"mailto:support@gradido.net\" style=\"color: #383838; font-weight: bold;\">support@gradido.net</a>
|
||||
<div> <img class=\"image\" alt=\"Gradido Logo\" src=\"https://gdd.gradido.net/img/brand/green.png\" style=\"width: 200px; margin-top: 30px; margin-bottom: 30px;\" width=\"200\"></div>
|
||||
<div><a class=\"terms_of_use\" href=\"https://gradido.net/de/impressum/\" target=\"_blank\" style=\"color: #9ca0a8;\">Impressum</a></div><br><a class=\"terms_of_use\" href=\"https://gradido.net/de/datenschutz/\" target=\"_blank\" style=\"color: #9ca0a8;\">Privacy Policy</a>
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@ -1390,12 +1390,12 @@ If the validity of the link has already expired, you can have a new link sent to
|
||||
|
||||
exports[`sendEmailVariants sendTransactionLinkRedeemedEmail result has the correct html as snapshot 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\\"en\\">
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta content=\\"multipart/html; charset=UTF-8\\" http-equiv=\\"content-type\\">
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1\\">
|
||||
<meta content=\"multipart/html; charset=UTF-8\" http-equiv=\"content-type\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<style>
|
||||
.wf-force-outline-none[tabindex=\\"-1\\"]:focus {
|
||||
.wf-force-outline-none[tabindex=\"-1\"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
@ -1521,37 +1521,37 @@ exports[`sendEmailVariants sendTransactionLinkRedeemedEmail result has the corre
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style=\\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\\">
|
||||
<div class=\\"container\\" style=\\"max-width: 680px; margin: 0 auto; display: block;\\">
|
||||
<body style=\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\">
|
||||
<div class=\"container\" style=\"max-width: 680px; margin: 0 auto; display: block;\">
|
||||
<header>
|
||||
<div class=\\"head\\"><img class=\\"head-logo\\" alt=\\"Gradido Logo\\" loading=\\"lazy\\" src=\\"cid:gradidoheader\\" style=\\"width: 100%; height: auto;\\"></div>
|
||||
<div class=\"head\"><img class=\"head-logo\" alt=\"Gradido Logo\" loading=\"lazy\" src=\"cid:gradidoheader\" style=\"width: 100%; height: auto;\"></div>
|
||||
</header>
|
||||
<div class=\\"wrapper\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Bibi Bloxberg has redeemed your Gradido link</h2>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"wrapper\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Bibi Bloxberg has redeemed your Gradido link</h2>
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Hello Peter Lustig,</p>
|
||||
<p>Bibi Bloxberg (bibi@bloxberg.de) has just redeemed your link.</p>
|
||||
</div>
|
||||
<div class=\\"content\\" style=\\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Transaction details</h2>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Amount: 17.65 GDD<br>Message: You deserve it! 🙏🏼<br>You can find transaction details in your Gradido account.
|
||||
</div><a class=\\"button-3\\" href=\\"http://localhost/transactions\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\\">To account</a>
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Please do not reply to this email.</div>
|
||||
<div class=\"content\" style=\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Transaction details</h2>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Amount: 17.65 GDD<br>Message: You deserve it! 🙏🏼<br>You can find transaction details in your Gradido account.
|
||||
</div><a class=\"button-3\" href=\"http://localhost/transactions\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\">To account</a>
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Please do not reply to this email.</div>
|
||||
</div>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Kind regards,<br>your Gradido team
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class=\\"w-container footer_01\\">
|
||||
<div class=\\"socialmedia\\" style=\\"display: flex; margin-top: 40px; max-width: 600px;\\"><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.facebook.com/groups/Gradido/\\" style=\\"width: 150px;\\"><img class=\\"bi-facebook\\" alt=\\"facebook\\" loading=\\"lazy\\" src=\\"cid:facebookicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://t.me/GradidoGruppe\\" style=\\"width: 150px;\\"><img class=\\"bi-telegram\\" alt=\\"Telegram\\" loading=\\"lazy\\" src=\\"cid:telegramicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://twitter.com/gradido\\" style=\\"width: 150px;\\"><img class=\\"bi-twitter\\" alt=\\"Twitter\\" loading=\\"lazy\\" src=\\"cid:twittericon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.youtube.com/c/GradidoNet\\" style=\\"width: 150px;\\"><img class=\\"bi-youtube\\" alt=\\"youtube\\" loading=\\"lazy\\" src=\\"cid:youtubeicon\\"></a></div>
|
||||
<div class=\\"line\\" style=\\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\\"></div>
|
||||
<div class=\\"footer\\" style=\\"padding-bottom: 20px;\\">
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">If you have any further questions, please contact our support.</div><a class=\\"footer_p2\\" href=\\"mailto:support@gradido.net\\" style=\\"color: #383838; font-weight: bold;\\">support@gradido.net</a>
|
||||
<div> <img class=\\"image\\" alt=\\"Gradido Logo\\" src=\\"https://gdd.gradido.net/img/brand/green.png\\" style=\\"width: 200px; margin-top: 30px; margin-bottom: 30px;\\" width=\\"200\\"></div>
|
||||
<div><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/impressum/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Impressum</a></div><br><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/datenschutz/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Privacy Policy</a>
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
<div class=\"w-container footer_01\">
|
||||
<div class=\"socialmedia\" style=\"display: flex; margin-top: 40px; max-width: 600px;\"><a class=\"slink\" target=\"_blank\" href=\"https://www.facebook.com/groups/Gradido/\" style=\"width: 150px;\"><img class=\"bi-facebook\" alt=\"facebook\" loading=\"lazy\" src=\"cid:facebookicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://t.me/GradidoGruppe\" style=\"width: 150px;\"><img class=\"bi-telegram\" alt=\"Telegram\" loading=\"lazy\" src=\"cid:telegramicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://twitter.com/gradido\" style=\"width: 150px;\"><img class=\"bi-twitter\" alt=\"Twitter\" loading=\"lazy\" src=\"cid:twittericon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://www.youtube.com/c/GradidoNet\" style=\"width: 150px;\"><img class=\"bi-youtube\" alt=\"youtube\" loading=\"lazy\" src=\"cid:youtubeicon\"></a></div>
|
||||
<div class=\"line\" style=\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\"></div>
|
||||
<div class=\"footer\" style=\"padding-bottom: 20px;\">
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">If you have any further questions, please contact our support.</div><a class=\"footer_p2\" href=\"mailto:support@gradido.net\" style=\"color: #383838; font-weight: bold;\">support@gradido.net</a>
|
||||
<div> <img class=\"image\" alt=\"Gradido Logo\" src=\"https://gdd.gradido.net/img/brand/green.png\" style=\"width: 200px; margin-top: 30px; margin-bottom: 30px;\" width=\"200\"></div>
|
||||
<div><a class=\"terms_of_use\" href=\"https://gradido.net/de/impressum/\" target=\"_blank\" style=\"color: #9ca0a8;\">Impressum</a></div><br><a class=\"terms_of_use\" href=\"https://gradido.net/de/datenschutz/\" target=\"_blank\" style=\"color: #9ca0a8;\">Privacy Policy</a>
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@ -1562,12 +1562,12 @@ exports[`sendEmailVariants sendTransactionLinkRedeemedEmail result has the corre
|
||||
|
||||
exports[`sendEmailVariants sendTransactionReceivedEmail result has the correct html as snapshot 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\\"en\\">
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta content=\\"multipart/html; charset=UTF-8\\" http-equiv=\\"content-type\\">
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1\\">
|
||||
<meta content=\"multipart/html; charset=UTF-8\" http-equiv=\"content-type\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<style>
|
||||
.wf-force-outline-none[tabindex=\\"-1\\"]:focus {
|
||||
.wf-force-outline-none[tabindex=\"-1\"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
@ -1693,40 +1693,40 @@ exports[`sendEmailVariants sendTransactionReceivedEmail result has the correct h
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style=\\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\\">
|
||||
<div class=\\"container\\" style=\\"max-width: 680px; margin: 0 auto; display: block;\\">
|
||||
<body style=\"display: block; font-family: 'Work Sans', sans-serif; font-size: 17px; text-align: center; text-align: -webkit-center; justify-content: center; padding: 0px; margin: 0px;\">
|
||||
<div class=\"container\" style=\"max-width: 680px; margin: 0 auto; display: block;\">
|
||||
<header>
|
||||
<div class=\\"head\\"><img class=\\"head-logo\\" alt=\\"Gradido Logo\\" loading=\\"lazy\\" src=\\"cid:gradidoheader\\" style=\\"width: 100%; height: auto;\\"></div>
|
||||
<div class=\"head\"><img class=\"head-logo\" alt=\"Gradido Logo\" loading=\"lazy\" src=\"cid:gradidoheader\" style=\"width: 100%; height: auto;\"></div>
|
||||
</header>
|
||||
<div class=\\"wrapper\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Bibi Bloxberg has sent you 37.40 Gradido</h2>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
<div class=\"wrapper\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Bibi Bloxberg has sent you 37.40 Gradido</h2>
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Hello Peter Lustig,</p>
|
||||
<p> You have just received 37.40 GDD from Bibi Bloxberg (<a href=\\"mailto:bibi@bloxberg.de?subject=RE%3A%20Bibi%20Bloxberg%20has%20sent%20you%2037.40%20Gradido\\">bibi@bloxberg.de</a>).
|
||||
<p> You have just received 37.40 GDD from Bibi Bloxberg (<a href=\"mailto:bibi@bloxberg.de?subject=RE%3A%20Bibi%20Bloxberg%20has%20sent%20you%2037.40%20Gradido\">bibi@bloxberg.de</a>).
|
||||
</p>
|
||||
</div>
|
||||
<div class=\\"content\\" style=\\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\\">
|
||||
<h2 style=\\"margin-top: 15px; color: #383838;\\">Message</h2>
|
||||
<div class=\\"child-left\\" style=\\"text-align: left;\\">
|
||||
<div class=\\"p_content\\" style=\\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\\">Du bist schon lustiger ;)</div>
|
||||
<div class=\"content\" style=\"display: block; width: 78%; margin: 40px 1% 40px 1%; padding: 20px 10% 40px 10%; border-radius: 24px; background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);\">
|
||||
<h2 style=\"margin-top: 15px; color: #383838;\">Message</h2>
|
||||
<div class=\"child-left\" style=\"text-align: left;\">
|
||||
<div class=\"p_content\" style=\"margin: 15px 0 15px 0; line-height: 26px; color: #696c72;\">Du bist schon lustiger ;)</div>
|
||||
</div>
|
||||
<div class=\\"child-right\\" style=\\"text-align: right;\\"><a class=\\"button-5\\" href=\\"mailto:bibi@bloxberg.de?subject=RE%3A%20Bibi%20Bloxberg%20has%20sent%20you%2037.40%20Gradido\\" style=\\"display: inline-block; padding: 9px 15px; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); margin: 25px 0 25px 0; background: linear-gradient(135deg, #53900c, #6e6e6e); font-size: 20px; font-weight: 600; color: #f5f5f5; width: auto; box-shadow: 20px 20px 25px; transition: all 0.3s ease;\\"><span class=\\"chatbox-wrapper\\" style=\\"margin-right: 8px;\\"><img class=\\"bi-chatbox\\" alt=\\"chatbox\\" loading=\\"lazy\\" src=\\"cid:chatboxicon\\" style=\\"margin-bottom: -5px;\\"></span><span>Reply</span></a>
|
||||
<div class=\"child-right\" style=\"text-align: right;\"><a class=\"button-5\" href=\"mailto:bibi@bloxberg.de?subject=RE%3A%20Bibi%20Bloxberg%20has%20sent%20you%2037.40%20Gradido\" style=\"display: inline-block; padding: 9px 15px; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); margin: 25px 0 25px 0; background: linear-gradient(135deg, #53900c, #6e6e6e); font-size: 20px; font-weight: 600; color: #f5f5f5; width: auto; box-shadow: 20px 20px 25px; transition: all 0.3s ease;\"><span class=\"chatbox-wrapper\" style=\"margin-right: 8px;\"><img class=\"bi-chatbox\" alt=\"chatbox\" loading=\"lazy\" src=\"cid:chatboxicon\" style=\"margin-bottom: -5px;\"></span><span>Reply</span></a>
|
||||
</div>
|
||||
</div><a class=\\"button-3\\" href=\\"http://localhost/transactions\\" style=\\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\\">To account</a>
|
||||
<div class=\\"text-block\\" style=\\"margin-top: 20px; color: #9ca0a8;\\">
|
||||
</div><a class=\"button-3\" href=\"http://localhost/transactions\" style=\"display: inline-block; padding: 9px 15px; color: white; border: 0; line-height: inherit; text-decoration: none; cursor: pointer; border-radius: 20px; background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); margin: 25px 0 25px 0; width: 50%;\">To account</a>
|
||||
<div class=\"text-block\" style=\"margin-top: 20px; color: #9ca0a8;\">
|
||||
<p>Kind regards,<br>your Gradido team
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class=\\"w-container footer_01\\">
|
||||
<div class=\\"socialmedia\\" style=\\"display: flex; margin-top: 40px; max-width: 600px;\\"><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.facebook.com/groups/Gradido/\\" style=\\"width: 150px;\\"><img class=\\"bi-facebook\\" alt=\\"facebook\\" loading=\\"lazy\\" src=\\"cid:facebookicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://t.me/GradidoGruppe\\" style=\\"width: 150px;\\"><img class=\\"bi-telegram\\" alt=\\"Telegram\\" loading=\\"lazy\\" src=\\"cid:telegramicon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://twitter.com/gradido\\" style=\\"width: 150px;\\"><img class=\\"bi-twitter\\" alt=\\"Twitter\\" loading=\\"lazy\\" src=\\"cid:twittericon\\"></a><a class=\\"slink\\" target=\\"_blank\\" href=\\"https://www.youtube.com/c/GradidoNet\\" style=\\"width: 150px;\\"><img class=\\"bi-youtube\\" alt=\\"youtube\\" loading=\\"lazy\\" src=\\"cid:youtubeicon\\"></a></div>
|
||||
<div class=\\"line\\" style=\\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\\"></div>
|
||||
<div class=\\"footer\\" style=\\"padding-bottom: 20px;\\">
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">If you have any further questions, please contact our support.</div><a class=\\"footer_p2\\" href=\\"mailto:support@gradido.net\\" style=\\"color: #383838; font-weight: bold;\\">support@gradido.net</a>
|
||||
<div> <img class=\\"image\\" alt=\\"Gradido Logo\\" src=\\"https://gdd.gradido.net/img/brand/green.png\\" style=\\"width: 200px; margin-top: 30px; margin-bottom: 30px;\\" width=\\"200\\"></div>
|
||||
<div><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/impressum/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Impressum</a></div><br><a class=\\"terms_of_use\\" href=\\"https://gradido.net/de/datenschutz/\\" target=\\"_blank\\" style=\\"color: #9ca0a8;\\">Privacy Policy</a>
|
||||
<div class=\\"footer_p1\\" style=\\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
<div class=\"w-container footer_01\">
|
||||
<div class=\"socialmedia\" style=\"display: flex; margin-top: 40px; max-width: 600px;\"><a class=\"slink\" target=\"_blank\" href=\"https://www.facebook.com/groups/Gradido/\" style=\"width: 150px;\"><img class=\"bi-facebook\" alt=\"facebook\" loading=\"lazy\" src=\"cid:facebookicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://t.me/GradidoGruppe\" style=\"width: 150px;\"><img class=\"bi-telegram\" alt=\"Telegram\" loading=\"lazy\" src=\"cid:telegramicon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://twitter.com/gradido\" style=\"width: 150px;\"><img class=\"bi-twitter\" alt=\"Twitter\" loading=\"lazy\" src=\"cid:twittericon\"></a><a class=\"slink\" target=\"_blank\" href=\"https://www.youtube.com/c/GradidoNet\" style=\"width: 150px;\"><img class=\"bi-youtube\" alt=\"youtube\" loading=\"lazy\" src=\"cid:youtubeicon\"></a></div>
|
||||
<div class=\"line\" style=\"width: 100%; height: 13px; margin-top: 40px; background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);\"></div>
|
||||
<div class=\"footer\" style=\"padding-bottom: 20px;\">
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">If you have any further questions, please contact our support.</div><a class=\"footer_p2\" href=\"mailto:support@gradido.net\" style=\"color: #383838; font-weight: bold;\">support@gradido.net</a>
|
||||
<div> <img class=\"image\" alt=\"Gradido Logo\" src=\"https://gdd.gradido.net/img/brand/green.png\" style=\"width: 200px; margin-top: 30px; margin-bottom: 30px;\" width=\"200\"></div>
|
||||
<div><a class=\"terms_of_use\" href=\"https://gradido.net/de/impressum/\" target=\"_blank\" style=\"color: #9ca0a8;\">Impressum</a></div><br><a class=\"terms_of_use\" href=\"https://gradido.net/de/datenschutz/\" target=\"_blank\" style=\"color: #9ca0a8;\">Privacy Policy</a>
|
||||
<div class=\"footer_p1\" style=\"margin-top: 30px; color: #9ca0a8; margin-bottom: 30px;\">Gradido-Akademie<br>Institut für Wirtschaftsbionik<br>Pfarrweg 2<br>74653 Künzelsau<br>Deutschland<br><br><br></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
1
core/src/emails/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './sendEmailVariants'
|
||||
7
core/src/emails/localization.test.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { i18n } from './localization'
|
||||
|
||||
describe('localization', () => {
|
||||
it('translate emails.accountMultiRegistration.contactSupport with Contact support', () => {
|
||||
expect(i18n.__('emails.accountMultiRegistration.contactSupport')).toBe('Contact support')
|
||||
})
|
||||
})
|
||||
31
core/src/emails/localization.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import en from './locales/en.json'
|
||||
import de from './locales/de.json'
|
||||
import { I18n } from 'i18n'
|
||||
|
||||
function flatten(obj: any, prefix: string = ''): any {
|
||||
const result: any = {}
|
||||
for (const key in obj) {
|
||||
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
||||
Object.assign(result, flatten(obj[key], prefix + key + '.'))
|
||||
} else {
|
||||
result[prefix + key] = obj[key]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export const i18n = new I18n({
|
||||
locales: ['en', 'de'],
|
||||
defaultLocale: 'en',
|
||||
staticCatalog: { en: flatten(en), de: flatten(de) },
|
||||
api: {
|
||||
__: 't', // now req.__ becomes req.t
|
||||
__n: 'tn', // and req.__n can be called as req.tn
|
||||
},
|
||||
register: global,
|
||||
mustacheConfig: {
|
||||
tags: ['{', '}'],
|
||||
disable: false,
|
||||
},
|
||||
})
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import { createTransport } from 'nodemailer'
|
||||
|
||||
import { i18n } from '@test/testSetup'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
|
||||
import { getLogger } from 'config-schema/test/testSetup'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import { CONFIG } from '../config'
|
||||
import { i18n } from './localization'
|
||||
import { getLogger } from '../../../config-schema/test/testSetup.bun'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '../config/const'
|
||||
import { sendEmailTranslated } from './sendEmailTranslated'
|
||||
import { mock, jest, describe, it, expect, beforeEach, afterAll } from 'bun:test'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.emails.sendEmailTranslated`)
|
||||
|
||||
@ -21,9 +19,8 @@ CONFIG.EMAIL_USERNAME = 'user'
|
||||
CONFIG.EMAIL_PASSWORD = 'pwd'
|
||||
CONFIG.EMAIL_TLS = true
|
||||
|
||||
jest.mock('nodemailer', () => {
|
||||
mock.module('nodemailer', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
createTransport: jest.fn(() => {
|
||||
return {
|
||||
sendMail: () => {
|
||||
@ -36,6 +33,13 @@ jest.mock('nodemailer', () => {
|
||||
}
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
jest.restoreAllMocks()
|
||||
})
|
||||
|
||||
const spySetLocale = jest.spyOn(i18n, 'setLocale')
|
||||
const spyTranslate = jest.spyOn(i18n, '__')
|
||||
|
||||
describe('sendEmailTranslated', () => {
|
||||
let result: Record<string, unknown> | boolean | null
|
||||
|
||||
@ -48,7 +52,7 @@ describe('sendEmailTranslated', () => {
|
||||
},
|
||||
template: 'accountMultiRegistration',
|
||||
locals: {
|
||||
locale: 'en',
|
||||
language: 'en',
|
||||
},
|
||||
})
|
||||
})
|
||||
@ -72,7 +76,7 @@ describe('sendEmailTranslated', () => {
|
||||
},
|
||||
template: 'accountMultiRegistration',
|
||||
locals: {
|
||||
locale: 'en',
|
||||
language: 'en',
|
||||
},
|
||||
})
|
||||
})
|
||||
@ -105,13 +109,13 @@ describe('sendEmailTranslated', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it.skip('calls "i18n.setLocale" with "en"', () => {
|
||||
expect(i18n.setLocale).toBeCalledWith('en')
|
||||
|
||||
it('calls "i18n.setLocale" with "en"', async () => {
|
||||
expect(spySetLocale).toBeCalledWith('en')
|
||||
})
|
||||
|
||||
it.skip('calls "i18n.__" for translation', () => {
|
||||
expect(i18n.__).toBeCalled()
|
||||
it('calls "i18n.__" for translation', () => {
|
||||
expect(spyTranslate).toBeCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@ -127,7 +131,7 @@ describe('sendEmailTranslated', () => {
|
||||
},
|
||||
template: 'accountMultiRegistration',
|
||||
locals: {
|
||||
locale: 'en',
|
||||
language: 'en',
|
||||
},
|
||||
})
|
||||
})
|
||||
@ -1,12 +1,16 @@
|
||||
import path from 'path'
|
||||
|
||||
import Email from 'email-templates'
|
||||
import i18n from 'i18n'
|
||||
import { i18n } from './localization'
|
||||
import { createTransport } from 'nodemailer'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import { CONFIG } from '../config'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '../config/const'
|
||||
import { getLogger } from 'log4js'
|
||||
import gradidoHeader from './templates/includes/gradido-header.jpeg'
|
||||
import facebookIcon from './templates/includes/facebook-icon.png'
|
||||
import telegramIcon from './templates/includes/telegram-icon.png'
|
||||
import twitterIcon from './templates/includes/twitter-icon.png'
|
||||
import youtubeIcon from './templates/includes/youtube-icon.png'
|
||||
import chatboxIcon from './templates/includes/chatbox-icon.png'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.emails.sendEmailTranslated`)
|
||||
|
||||
@ -21,7 +25,7 @@ export const sendEmailTranslated = async ({
|
||||
}
|
||||
template: string
|
||||
locals: Record<string, unknown>
|
||||
}): Promise<Record<string, unknown> | boolean | null> => {
|
||||
}): Promise<Record<string, unknown> | boolean | null | Error> => {
|
||||
// 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'
|
||||
|
||||
if (!CONFIG.EMAIL) {
|
||||
@ -31,7 +35,6 @@ export const sendEmailTranslated = async ({
|
||||
|
||||
// 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.substring(0, 3)}...` +
|
||||
@ -45,6 +48,7 @@ export const sendEmailTranslated = async ({
|
||||
)
|
||||
receiver.to = CONFIG.EMAIL_TEST_RECEIVER
|
||||
}
|
||||
|
||||
const transport = createTransport({
|
||||
host: CONFIG.EMAIL_SMTP_HOST,
|
||||
port: CONFIG.EMAIL_SMTP_PORT,
|
||||
@ -56,8 +60,7 @@ export const sendEmailTranslated = async ({
|
||||
},
|
||||
})
|
||||
|
||||
i18n.setLocale(locals.locale as string) // for email
|
||||
|
||||
i18n.setLocale(locals.language as string) // for email
|
||||
// TESTING: see 'README.md'
|
||||
const email = new Email({
|
||||
message: {
|
||||
@ -66,9 +69,7 @@ export const sendEmailTranslated = async ({
|
||||
send: CONFIG.EMAIL,
|
||||
transport,
|
||||
preview: false,
|
||||
// i18n, // is only needed if you don't install i18n
|
||||
})
|
||||
|
||||
const resultSend = await email
|
||||
.send({
|
||||
template: path.join(__dirname, 'templates', template),
|
||||
@ -76,38 +77,39 @@ export const sendEmailTranslated = async ({
|
||||
...receiver,
|
||||
attachments: [
|
||||
{
|
||||
filename: 'gradido-header.jpeg',
|
||||
path: path.join(__dirname, 'templates/includes/gradido-header.jpeg'),
|
||||
// filename: 'gradido-header.jpeg',
|
||||
content: gradidoHeader,
|
||||
cid: 'gradidoheader',
|
||||
},
|
||||
{
|
||||
filename: 'facebook-icon.png',
|
||||
path: path.join(__dirname, 'templates/includes/facebook-icon.png'),
|
||||
// filename: 'facebook-icon.png',
|
||||
content: facebookIcon,
|
||||
cid: 'facebookicon',
|
||||
},
|
||||
{
|
||||
filename: 'telegram-icon.png',
|
||||
path: path.join(__dirname, 'templates/includes/telegram-icon.png'),
|
||||
// filename: 'telegram-icon.png',
|
||||
content: telegramIcon,
|
||||
cid: 'telegramicon',
|
||||
},
|
||||
{
|
||||
filename: 'twitter-icon.png',
|
||||
path: path.join(__dirname, 'templates/includes/twitter-icon.png'),
|
||||
// filename: 'twitter-icon.png',
|
||||
content: twitterIcon,
|
||||
cid: 'twittericon',
|
||||
},
|
||||
{
|
||||
filename: 'youtube-icon.png',
|
||||
path: path.join(__dirname, 'templates/includes/youtube-icon.png'),
|
||||
// filename: 'youtube-icon.png',
|
||||
content: youtubeIcon,
|
||||
cid: 'youtubeicon',
|
||||
},
|
||||
{
|
||||
filename: 'chatbox-icon.png',
|
||||
path: path.join(__dirname, 'templates/includes/chatbox-icon.png'),
|
||||
// filename: 'chatbox-icon.png',
|
||||
content: chatboxIcon,
|
||||
cid: 'chatboxicon',
|
||||
},
|
||||
],
|
||||
},
|
||||
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'
|
||||
// t: i18n.__.bind(i18n),
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
logger.error('Error sending notification email', error)
|
||||
609
core/src/emails/sendEmailVariants.test.ts
Normal file
@ -0,0 +1,609 @@
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { CONFIG } from '../config'
|
||||
|
||||
import * as sendEmailTranslatedApi from './sendEmailTranslated'
|
||||
import {
|
||||
sendAccountActivationEmail,
|
||||
sendAccountMultiRegistrationEmail,
|
||||
sendAddedContributionMessageEmail,
|
||||
sendContributionChangedByModeratorEmail,
|
||||
sendContributionConfirmedEmail,
|
||||
sendContributionDeletedEmail,
|
||||
sendContributionDeniedEmail,
|
||||
sendResetPasswordEmail,
|
||||
sendTransactionLinkRedeemedEmail,
|
||||
sendTransactionReceivedEmail,
|
||||
} from './sendEmailVariants'
|
||||
|
||||
const testMailServerHost = 'localhost'
|
||||
const testMailServerPort = 1025
|
||||
const testMailTLS = false
|
||||
|
||||
CONFIG.EMAIL = true
|
||||
CONFIG.EMAIL_SENDER = 'info@gradido.net'
|
||||
CONFIG.EMAIL_SMTP_HOST = testMailServerHost
|
||||
CONFIG.EMAIL_SMTP_PORT = testMailServerPort
|
||||
CONFIG.EMAIL_TLS = testMailTLS
|
||||
|
||||
jest.mock('nodemailer', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
createTransport: jest.fn(() => {
|
||||
return {
|
||||
sendMail: () => {
|
||||
return {
|
||||
messageId: 'message',
|
||||
}
|
||||
},
|
||||
}
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
const sendEmailTranslatedSpy = jest.spyOn(sendEmailTranslatedApi, 'sendEmailTranslated')
|
||||
|
||||
describe('sendEmailVariants', () => {
|
||||
let result: any
|
||||
const contributionFrontendLink =
|
||||
'https://gradido.net/contributions/own-contributions/1#contributionListItem-1'
|
||||
|
||||
describe('sendAddedContributionMessageEmail', () => {
|
||||
beforeAll(async () => {
|
||||
result = await sendAddedContributionMessageEmail({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
language: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
contributionMemo: 'My contribution.',
|
||||
contributionFrontendLink,
|
||||
message: 'My message.',
|
||||
})
|
||||
})
|
||||
|
||||
describe('calls "sendEmailTranslated"', () => {
|
||||
it('with expected parameters', () => {
|
||||
expect(sendEmailTranslatedSpy).toBeCalledWith({
|
||||
receiver: {
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
},
|
||||
template: 'addedContributionMessage',
|
||||
locals: expect.objectContaining({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
language: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
contributionMemo: 'My contribution.',
|
||||
contributionFrontendLink,
|
||||
message: 'My message.',
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
}),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('result', () => {
|
||||
it('is the expected object', () => {
|
||||
// bun testrunner bug, toMatchObject mess with 'result'
|
||||
const resultClone = JSON.parse(JSON.stringify(result))
|
||||
expect(resultClone).toMatchObject({
|
||||
originalMessage: expect.objectContaining({
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
from: 'Gradido (emails.general.doNotAnswer) <info@gradido.net>',
|
||||
attachments: expect.any(Array),
|
||||
subject: 'Message about your common good contribution',
|
||||
html: expect.any(String),
|
||||
text: expect.stringContaining('MESSAGE ABOUT YOUR COMMON GOOD CONTRIBUTION'),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
it('has the correct html as snapshot', () => {
|
||||
expect(result.originalMessage.html).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('sendAccountActivationEmail', () => {
|
||||
beforeAll(async () => {
|
||||
result = await sendAccountActivationEmail({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
language: 'en',
|
||||
activationLink: 'http://localhost/checkEmail/6627633878930542284',
|
||||
timeDurationObject: { hours: 23, minutes: 30 },
|
||||
})
|
||||
})
|
||||
|
||||
describe('calls "sendEmailTranslated"', () => {
|
||||
it('with expected parameters', () => {
|
||||
expect(sendEmailTranslatedSpy).toBeCalledWith({
|
||||
receiver: {
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
},
|
||||
template: 'accountActivation',
|
||||
locals: expect.objectContaining({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
language: 'en',
|
||||
activationLink: 'http://localhost/checkEmail/6627633878930542284',
|
||||
timeDurationObject: { hours: 23, minutes: 30 },
|
||||
resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD,
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
communityURL: CONFIG.COMMUNITY_URL,
|
||||
}),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('result', () => {
|
||||
it('is the expected object', () => {
|
||||
// bun testrunner bug, toMatchObject mess with 'result'
|
||||
const resultClone = JSON.parse(JSON.stringify(result))
|
||||
expect(resultClone).toMatchObject({
|
||||
originalMessage: expect.objectContaining({
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
from: 'Gradido (emails.general.doNotAnswer) <info@gradido.net>',
|
||||
attachments: expect.any(Array),
|
||||
subject: 'Email Verification',
|
||||
html: expect.any(String),
|
||||
text: expect.stringContaining('EMAIL VERIFICATION'),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
it('has the correct html as snapshot', () => {
|
||||
expect(result.originalMessage.html).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
|
||||
describe('sendAccountMultiRegistrationEmail', () => {
|
||||
beforeAll(async () => {
|
||||
result = await sendAccountMultiRegistrationEmail({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
language: 'en',
|
||||
})
|
||||
})
|
||||
|
||||
describe('calls "sendEmailTranslated"', () => {
|
||||
it('with expected parameters', () => {
|
||||
expect(sendEmailTranslatedSpy).toBeCalledWith({
|
||||
receiver: {
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
},
|
||||
template: 'accountMultiRegistration',
|
||||
locals: {
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
locale: 'en',
|
||||
resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD,
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
communityURL: CONFIG.COMMUNITY_URL,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
describe('result', () => {
|
||||
it('is the expected object', () => {
|
||||
expect(result).toMatchObject({
|
||||
originalMessage: expect.objectContaining({
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
from: 'Gradido (emails.general.doNotAnswer) <info@gradido.net>',
|
||||
attachments: expect.any(Array),
|
||||
subject: 'Try To Register Again With Your Email',
|
||||
html: expect.any(String),
|
||||
text: expect.stringContaining('TRY TO REGISTER AGAIN WITH YOUR EMAIL'),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
it('has the correct html as snapshot', () => {
|
||||
expect(result.originalMessage.html).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('sendContributionConfirmedEmail', () => {
|
||||
beforeAll(async () => {
|
||||
result = await sendContributionConfirmedEmail({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
language: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
contributionMemo: 'My contribution.',
|
||||
contributionAmount: new Decimal(23.54),
|
||||
contributionFrontendLink,
|
||||
})
|
||||
})
|
||||
|
||||
describe('calls "sendEmailTranslated"', () => {
|
||||
it('with expected parameters', () => {
|
||||
expect(sendEmailTranslatedSpy).toBeCalledWith({
|
||||
receiver: {
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
},
|
||||
template: 'contributionConfirmed',
|
||||
locals: {
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
locale: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
contributionMemo: 'My contribution.',
|
||||
contributionAmount: '23.54',
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
contributionFrontendLink,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('result', () => {
|
||||
it('is the expected object', () => {
|
||||
expect(result).toMatchObject({
|
||||
originalMessage: expect.objectContaining({
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
from: 'Gradido (emails.general.doNotAnswer) <info@gradido.net>',
|
||||
attachments: expect.any(Array),
|
||||
subject: 'Your contribution to the common good was confirmed',
|
||||
html: expect.any(String),
|
||||
text: expect.stringContaining('YOUR CONTRIBUTION TO THE COMMON GOOD WAS CONFIRMED'),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
it('has the correct html as snapshot', () => {
|
||||
expect(result.originalMessage.html).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('sendContributionChangedByModeratorEmail', () => {
|
||||
beforeAll(async () => {
|
||||
result = await sendContributionChangedByModeratorEmail({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
language: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
contributionMemo: 'My contribution.',
|
||||
contributionMemoUpdated: 'This is a better contribution memo.',
|
||||
contributionFrontendLink,
|
||||
})
|
||||
})
|
||||
|
||||
describe('calls "sendEmailTranslated"', () => {
|
||||
it('with expected parameters', () => {
|
||||
expect(sendEmailTranslatedSpy).toBeCalledWith({
|
||||
receiver: {
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
},
|
||||
template: 'contributionChangedByModerator',
|
||||
locals: {
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
locale: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
contributionMemo: 'My contribution.',
|
||||
contributionMemoUpdated: 'This is a better contribution memo.',
|
||||
contributionFrontendLink,
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('result', () => {
|
||||
it('is the expected object', () => {
|
||||
expect(result).toMatchObject({
|
||||
originalMessage: expect.objectContaining({
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
from: 'Gradido (emails.general.doNotAnswer) <info@gradido.net>',
|
||||
attachments: expect.any(Array),
|
||||
subject: 'Your common good contribution has been changed',
|
||||
html: expect.any(String),
|
||||
text: expect.stringContaining('YOUR COMMON GOOD CONTRIBUTION HAS BEEN CHANGED'),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
it('has the correct html as snapshot', () => {
|
||||
expect(result.originalMessage.html).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('sendContributionDeniedEmail', () => {
|
||||
beforeAll(async () => {
|
||||
result = await sendContributionDeniedEmail({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
language: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
contributionMemo: 'My contribution.',
|
||||
contributionFrontendLink,
|
||||
})
|
||||
})
|
||||
|
||||
describe('calls "sendEmailTranslated"', () => {
|
||||
it('with expected parameters', () => {
|
||||
expect(sendEmailTranslatedSpy).toBeCalledWith({
|
||||
receiver: {
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
},
|
||||
template: 'contributionDenied',
|
||||
locals: {
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
locale: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
contributionMemo: 'My contribution.',
|
||||
contributionFrontendLink,
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('result', () => {
|
||||
it('has expected result', () => {
|
||||
expect(result).toMatchObject({
|
||||
originalMessage: expect.objectContaining({
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
from: 'Gradido (emails.general.doNotAnswer) <info@gradido.net>',
|
||||
attachments: expect.any(Array),
|
||||
subject: 'Your common good contribution was rejected',
|
||||
html: expect.any(String),
|
||||
text: expect.stringContaining('YOUR COMMON GOOD CONTRIBUTION WAS REJECTED'),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
it('has the correct html as snapshot', () => {
|
||||
expect(result.originalMessage.html).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('sendContributionDeletedEmail', () => {
|
||||
beforeAll(async () => {
|
||||
result = await sendContributionDeletedEmail({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
language: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
contributionMemo: 'My contribution.',
|
||||
contributionFrontendLink,
|
||||
})
|
||||
})
|
||||
|
||||
describe('calls "sendEmailTranslated"', () => {
|
||||
it('with expected parameters', () => {
|
||||
expect(sendEmailTranslatedSpy).toBeCalledWith({
|
||||
receiver: {
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
},
|
||||
template: 'contributionDeleted',
|
||||
locals: {
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
locale: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
contributionMemo: 'My contribution.',
|
||||
contributionFrontendLink,
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('result', () => {
|
||||
it('is the expected object', () => {
|
||||
expect(result).toMatchObject({
|
||||
originalMessage: expect.objectContaining({
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
from: 'Gradido (emails.general.doNotAnswer) <info@gradido.net>',
|
||||
attachments: expect.any(Array),
|
||||
subject: 'Your common good contribution was deleted',
|
||||
html: expect.any(String),
|
||||
text: expect.stringContaining('YOUR COMMON GOOD CONTRIBUTION WAS DELETED'),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
it('has the correct html as snapshot', () => {
|
||||
expect(result.originalMessage.html).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('sendResetPasswordEmail', () => {
|
||||
beforeAll(async () => {
|
||||
result = await sendResetPasswordEmail({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
language: 'en',
|
||||
resetLink: 'http://localhost/reset-password/3762660021544901417',
|
||||
timeDurationObject: { hours: 23, minutes: 30 },
|
||||
})
|
||||
})
|
||||
|
||||
describe('calls "sendEmailTranslated"', () => {
|
||||
it('with expected parameters', () => {
|
||||
expect(sendEmailTranslatedSpy).toBeCalledWith({
|
||||
receiver: {
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
},
|
||||
template: 'resetPassword',
|
||||
locals: {
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
locale: 'en',
|
||||
resetLink: 'http://localhost/reset-password/3762660021544901417',
|
||||
timeDurationObject: { hours: 23, minutes: 30 },
|
||||
resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD,
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
communityURL: CONFIG.COMMUNITY_URL,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('result', () => {
|
||||
it('is the expected object', () => {
|
||||
expect(result).toMatchObject({
|
||||
originalMessage: expect.objectContaining({
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
from: 'Gradido (emails.general.doNotAnswer) <info@gradido.net>',
|
||||
attachments: expect.any(Array),
|
||||
subject: 'Reset password',
|
||||
html: expect.any(String),
|
||||
text: expect.stringContaining('RESET PASSWORD'),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
it('has the correct html as snapshot', () => {
|
||||
expect(result.originalMessage.html).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('sendTransactionLinkRedeemedEmail', () => {
|
||||
beforeAll(async () => {
|
||||
result = await sendTransactionLinkRedeemedEmail({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
language: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
senderEmail: 'bibi@bloxberg.de',
|
||||
transactionMemo: 'You deserve it! 🙏🏼',
|
||||
transactionAmount: new Decimal(17.65),
|
||||
})
|
||||
})
|
||||
|
||||
describe('calls "sendEmailTranslated"', () => {
|
||||
it('with expected parameters', () => {
|
||||
expect(sendEmailTranslatedSpy).toBeCalledWith({
|
||||
receiver: {
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
},
|
||||
template: 'transactionLinkRedeemed',
|
||||
locals: {
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
locale: 'en',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
senderEmail: 'bibi@bloxberg.de',
|
||||
transactionMemo: 'You deserve it! 🙏🏼',
|
||||
transactionAmount: '17.65',
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
communityURL: CONFIG.COMMUNITY_URL,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('result', () => {
|
||||
it('is the expected object', () => {
|
||||
expect(result).toMatchObject({
|
||||
originalMessage: expect.objectContaining({
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
from: 'Gradido (emails.general.doNotAnswer) <info@gradido.net>',
|
||||
attachments: expect.any(Array),
|
||||
subject: 'Bibi Bloxberg has redeemed your Gradido link',
|
||||
html: expect.any(String),
|
||||
text: expect.stringContaining('BIBI BLOXBERG HAS REDEEMED YOUR GRADIDO LINK'),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
it('has the correct html as snapshot', () => {
|
||||
expect(result.originalMessage.html).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('sendTransactionReceivedEmail', () => {
|
||||
beforeAll(async () => {
|
||||
result = await sendTransactionReceivedEmail({
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
language: 'en',
|
||||
memo: 'Du bist schon lustiger ;)',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
senderEmail: 'bibi@bloxberg.de',
|
||||
transactionAmount: new Decimal(37.4),
|
||||
})
|
||||
})
|
||||
|
||||
describe('calls "sendEmailTranslated"', () => {
|
||||
it('with expected parameters', () => {
|
||||
expect(sendEmailTranslatedSpy).toBeCalledWith({
|
||||
receiver: {
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
},
|
||||
template: 'transactionReceived',
|
||||
locals: {
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
locale: 'en',
|
||||
memo: 'Du bist schon lustiger ;)',
|
||||
senderFirstName: 'Bibi',
|
||||
senderLastName: 'Bloxberg',
|
||||
senderEmail: 'bibi@bloxberg.de',
|
||||
transactionAmount: '37.40',
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
communityURL: CONFIG.COMMUNITY_URL,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('result', () => {
|
||||
it('is the expected object', () => {
|
||||
expect(result).toMatchObject({
|
||||
originalMessage: expect.objectContaining({
|
||||
to: 'Peter Lustig <peter@lustig.de>',
|
||||
from: 'Gradido (emails.general.doNotAnswer) <info@gradido.net>',
|
||||
attachments: expect.any(Array),
|
||||
subject: 'Bibi Bloxberg has sent you 37.40 Gradido',
|
||||
html: expect.any(String),
|
||||
text: expect.stringContaining('BIBI BLOXBERG HAS SENT YOU 37.40 GRADIDO'),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
it('has the correct html as snapshot', () => {
|
||||
expect(result.originalMessage.html).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
*/
|
||||
})
|
||||
179
core/src/emails/sendEmailVariants.ts
Normal file
@ -0,0 +1,179 @@
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
|
||||
import { CONFIG } from '../config'
|
||||
import { decimalSeparatorByLanguage } from '../util/utilities'
|
||||
|
||||
import { sendEmailTranslated } from './sendEmailTranslated'
|
||||
|
||||
export interface EmailCommonData {
|
||||
firstName: string
|
||||
lastName: string
|
||||
email: string
|
||||
language: string
|
||||
}
|
||||
|
||||
export interface ContributionEmailCommonData {
|
||||
senderFirstName: string
|
||||
senderLastName: string
|
||||
contributionMemo: string
|
||||
contributionFrontendLink: string
|
||||
}
|
||||
|
||||
function getEmailCommonLocales(): Record<string, unknown> {
|
||||
return {
|
||||
supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL,
|
||||
resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD,
|
||||
communityURL: CONFIG.COMMUNITY_URL,
|
||||
}
|
||||
}
|
||||
|
||||
export const sendAddedContributionMessageEmail = (
|
||||
data: EmailCommonData & ContributionEmailCommonData & {
|
||||
message: string
|
||||
},
|
||||
): Promise<Record<string, unknown> | boolean | null | Error> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: {
|
||||
to: `${data.firstName} ${data.lastName} <${data.email}>`,
|
||||
},
|
||||
template: 'addedContributionMessage',
|
||||
locals: {
|
||||
...data,
|
||||
...getEmailCommonLocales(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendAccountActivationEmail = (data: EmailCommonData & {
|
||||
activationLink: string
|
||||
timeDurationObject: Record<string, unknown>
|
||||
logoUrl?: string | null
|
||||
}): Promise<Record<string, unknown> | boolean | null | Error> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'accountActivation',
|
||||
locals: {
|
||||
...data,
|
||||
...getEmailCommonLocales(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendAccountMultiRegistrationEmail = (data: EmailCommonData): Promise<Record<string, unknown> | boolean | null | Error> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'accountMultiRegistration',
|
||||
locals: {
|
||||
...data,
|
||||
...getEmailCommonLocales(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendContributionConfirmedEmail = (
|
||||
data: EmailCommonData & ContributionEmailCommonData & {
|
||||
contributionAmount: Decimal
|
||||
},
|
||||
): Promise<Record<string, unknown> | boolean | null | Error> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'contributionConfirmed',
|
||||
locals: {
|
||||
...data,
|
||||
...getEmailCommonLocales(),
|
||||
contributionAmount: decimalSeparatorByLanguage(data.contributionAmount, data.language),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendContributionChangedByModeratorEmail = (
|
||||
data: EmailCommonData & ContributionEmailCommonData & {
|
||||
contributionMemoUpdated: string
|
||||
},
|
||||
): Promise<Record<string, unknown> | boolean | null | Error> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'contributionChangedByModerator',
|
||||
locals: {
|
||||
...data,
|
||||
...getEmailCommonLocales(),
|
||||
contributionMemoUpdated: data.contributionMemoUpdated,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendContributionDeletedEmail = (
|
||||
data: EmailCommonData & ContributionEmailCommonData,
|
||||
): Promise<Record<string, unknown> | boolean | null | Error> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'contributionDeleted',
|
||||
locals: {
|
||||
...data,
|
||||
...getEmailCommonLocales(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendContributionDeniedEmail = (
|
||||
data: EmailCommonData & ContributionEmailCommonData,
|
||||
): Promise<Record<string, unknown> | boolean | null | Error> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'contributionDenied',
|
||||
locals: {
|
||||
...data,
|
||||
...getEmailCommonLocales(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendResetPasswordEmail = (data: EmailCommonData & {
|
||||
resetLink: string
|
||||
timeDurationObject: Record<string, unknown>
|
||||
}): Promise<Record<string, unknown> | boolean | null | Error> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'resetPassword',
|
||||
locals: {
|
||||
...data,
|
||||
...getEmailCommonLocales(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendTransactionLinkRedeemedEmail = (data: EmailCommonData & {
|
||||
senderFirstName: string
|
||||
senderLastName: string
|
||||
senderEmail: string
|
||||
transactionMemo: string
|
||||
transactionAmount: Decimal
|
||||
}): Promise<Record<string, unknown> | boolean | null | Error> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'transactionLinkRedeemed',
|
||||
locals: {
|
||||
...data,
|
||||
transactionAmount: decimalSeparatorByLanguage(data.transactionAmount, data.language),
|
||||
...getEmailCommonLocales(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const sendTransactionReceivedEmail = (data: EmailCommonData & {
|
||||
senderFirstName: string
|
||||
senderLastName: string
|
||||
senderEmail: string
|
||||
memo: string
|
||||
transactionAmount: Decimal
|
||||
}): Promise<Record<string, unknown> | boolean | null | Error> => {
|
||||
return sendEmailTranslated({
|
||||
receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` },
|
||||
template: 'transactionReceived',
|
||||
locals: {
|
||||
...data,
|
||||
transactionAmount: decimalSeparatorByLanguage(data.transactionAmount, data.language),
|
||||
...getEmailCommonLocales(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
Before Width: | Height: | Size: 341 B After Width: | Height: | Size: 341 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 323 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@ -1,4 +1,8 @@
|
||||
import { TransactionLink as DbTransactionLink, User as DbUser } from "database";
|
||||
import { TransactionLink as DbTransactionLink, User as DbUser } from 'database'
|
||||
import { getLogger } from 'log4js'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '../../config/const'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.logic.storeLinkAsRedeemed`)
|
||||
|
||||
export async function storeLinkAsRedeemed(
|
||||
dbTransactionLink: DbTransactionLink,
|
||||
@ -11,7 +15,7 @@ export async function storeLinkAsRedeemed(
|
||||
await DbTransactionLink.save(dbTransactionLink)
|
||||
return true
|
||||
} catch (err) {
|
||||
console.error('error in storeLinkAsRedeemed;', err)
|
||||
logger.error('error: ', err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,7 @@ export * from './graphql/logic/settlePendingSenderTransaction'
|
||||
export * from './graphql/logic/storeForeignUser'
|
||||
export * from './graphql/model/Decay'
|
||||
export * from './graphql/model/EncryptedTransferArgs'
|
||||
export * from './emails'
|
||||
export * from './util/calculateSenderBalance'
|
||||
export * from './util/utilities'
|
||||
export * from './validation/user'
|
||||
|
||||
15
core/src/types/images.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// biome-ignore lint/style/noDefaultExport: Asset modules use default export by convention
|
||||
declare module '*.jpg' {
|
||||
const value: string
|
||||
export default value
|
||||
}
|
||||
declare module '*.jpeg' {
|
||||
const value: string
|
||||
export default value
|
||||
}
|
||||
declare module '*.png' {
|
||||
const value: string
|
||||
export default value
|
||||
}
|
||||
|
||||
|
||||