diff --git a/admin/src/graphql/searchUsers.js b/admin/src/graphql/searchUsers.js
index 3e33fe96b..15fb8da32 100644
--- a/admin/src/graphql/searchUsers.js
+++ b/admin/src/graphql/searchUsers.js
@@ -1,12 +1,19 @@
import gql from 'graphql-tag'
export const searchUsers = gql`
- query ($searchText: String!, $currentPage: Int, $pageSize: Int, $filters: SearchUsersFilters) {
+ query (
+ $query: String!
+ $filters: SearchUsersFilters
+ $currentPage: Int = 0
+ $pageSize: Int = 25
+ $order: Order = ASC
+ ) {
searchUsers(
- searchText: $searchText
+ query: $query
+ filters: $filters
currentPage: $currentPage
pageSize: $pageSize
- filters: $filters
+ order: $order
) {
userCount
userList {
diff --git a/admin/src/pages/UserSearch.spec.js b/admin/src/pages/UserSearch.spec.js
index 0d145cb89..1f9b0ce6e 100644
--- a/admin/src/pages/UserSearch.spec.js
+++ b/admin/src/pages/UserSearch.spec.js
@@ -10,11 +10,20 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
userCount: 4,
userList: [
{
- userId: 1,
- firstName: 'Bibi',
- lastName: 'Bloxberg',
- email: 'bibi@bloxberg.de',
- creation: [200, 400, 600],
+ userId: 4,
+ firstName: 'New',
+ lastName: 'User',
+ email: 'new@user.ch',
+ creation: [1000, 1000, 1000],
+ emailChecked: false,
+ deletedAt: null,
+ },
+ {
+ userId: 3,
+ firstName: 'Peter',
+ lastName: 'Lustig',
+ email: 'peter@lustig.de',
+ creation: [0, 0, 0],
emailChecked: true,
deletedAt: null,
},
@@ -28,23 +37,14 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
deletedAt: new Date(),
},
{
- userId: 3,
- firstName: 'Peter',
- lastName: 'Lustig',
- email: 'peter@lustig.de',
- creation: [0, 0, 0],
+ userId: 1,
+ firstName: 'Bibi',
+ lastName: 'Bloxberg',
+ email: 'bibi@bloxberg.de',
+ creation: [200, 400, 600],
emailChecked: true,
deletedAt: null,
},
- {
- userId: 4,
- firstName: 'New',
- lastName: 'User',
- email: 'new@user.ch',
- creation: [1000, 1000, 1000],
- emailChecked: false,
- deletedAt: null,
- },
],
},
},
@@ -79,9 +79,10 @@ describe('UserSearch', () => {
expect(apolloQueryMock).toBeCalledWith(
expect.objectContaining({
variables: {
- searchText: '',
+ query: '',
currentPage: 1,
pageSize: 25,
+ order: 'DESC',
filters: {
byActivated: null,
byDeleted: null,
@@ -100,9 +101,10 @@ describe('UserSearch', () => {
expect(apolloQueryMock).toBeCalledWith(
expect.objectContaining({
variables: {
- searchText: '',
+ query: '',
currentPage: 1,
pageSize: 25,
+ order: 'DESC',
filters: {
byActivated: false,
byDeleted: null,
@@ -122,9 +124,10 @@ describe('UserSearch', () => {
expect(apolloQueryMock).toBeCalledWith(
expect.objectContaining({
variables: {
- searchText: '',
+ query: '',
currentPage: 1,
pageSize: 25,
+ order: 'DESC',
filters: {
byActivated: null,
byDeleted: true,
@@ -144,9 +147,10 @@ describe('UserSearch', () => {
expect(apolloQueryMock).toBeCalledWith(
expect.objectContaining({
variables: {
- searchText: '',
+ query: '',
currentPage: 2,
pageSize: 25,
+ order: 'DESC',
filters: {
byActivated: null,
byDeleted: null,
@@ -166,9 +170,10 @@ describe('UserSearch', () => {
expect(apolloQueryMock).toBeCalledWith(
expect.objectContaining({
variables: {
- searchText: 'search string',
+ query: 'search string',
currentPage: 1,
pageSize: 25,
+ order: 'DESC',
filters: {
byActivated: null,
byDeleted: null,
@@ -185,9 +190,10 @@ describe('UserSearch', () => {
expect(apolloQueryMock).toBeCalledWith(
expect.objectContaining({
variables: {
- searchText: '',
+ query: '',
currentPage: 1,
pageSize: 25,
+ order: 'DESC',
filters: {
byActivated: null,
byDeleted: null,
diff --git a/admin/src/pages/UserSearch.vue b/admin/src/pages/UserSearch.vue
index 8f24181ee..d4e4083c2 100644
--- a/admin/src/pages/UserSearch.vue
+++ b/admin/src/pages/UserSearch.vue
@@ -49,7 +49,7 @@
pills
size="lg"
v-model="currentPage"
- per-page="perPage"
+ :per-page="perPage"
:total-rows="rows"
align="center"
:hide-ellipsis="true"
@@ -97,10 +97,11 @@ export default {
.query({
query: searchUsers,
variables: {
- searchText: this.criteria,
+ query: this.criteria,
+ filters: this.filters,
currentPage: this.currentPage,
pageSize: this.perPage,
- filters: this.filters,
+ order: 'DESC',
},
fetchPolicy: 'no-cache',
})
diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js
index 0007fd125..e853c8bf6 100644
--- a/backend/.eslintrc.js
+++ b/backend/.eslintrc.js
@@ -25,10 +25,12 @@ module.exports = {
},
node: true,
},
+ // the parser cannot handle the split sodium import
+ 'import/ignore': ['sodium-native'],
},
rules: {
'no-console': 'error',
- camelcase: ['error', { allow: ['FederationClient_*'] }],
+ camelcase: ['error', { allow: ['FederationClient_*', 'crypto_*', 'randombytes_random'] }],
'no-debugger': 'error',
'prettier/prettier': [
'error',
@@ -58,7 +60,10 @@ module.exports = {
'import/no-dynamic-require': 'error',
'import/no-internal-modules': 'off',
'import/no-relative-packages': 'error',
- 'import/no-relative-parent-imports': ['error', { ignore: ['@/*', 'random-bigint'] }],
+ 'import/no-relative-parent-imports': [
+ 'error',
+ { ignore: ['@/*', 'random-bigint', 'sodium-native'] },
+ ],
'import/no-self-import': 'error',
'import/no-unresolved': 'error',
'import/no-useless-path-segments': 'error',
diff --git a/backend/@types/sodium-native/index.d.ts b/backend/@types/sodium-native/index.d.ts
new file mode 100644
index 000000000..773d85ee5
--- /dev/null
+++ b/backend/@types/sodium-native/index.d.ts
@@ -0,0 +1,8 @@
+// eslint-disable-next-line import/no-unresolved
+export * from '@/node_modules/@types/sodium-native'
+
+declare module 'sodium-native' {
+ export function crypto_hash_sha512_init(state: Buffer, key?: Buffer, outlen?: Buffer): void
+ export function crypto_hash_sha512_update(state: Buffer, input: Buffer): void
+ export function crypto_hash_sha512_final(state: Buffer, out: Buffer): void
+}
diff --git a/backend/package.json b/backend/package.json
index 4910ae3ce..14c67c01d 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -56,6 +56,7 @@
"@types/lodash.clonedeep": "^4.5.6",
"@types/node": "^16.10.3",
"@types/nodemailer": "^6.4.4",
+ "@types/sodium-native": "^2.3.5",
"@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "^5.57.1",
"@typescript-eslint/parser": "^5.57.1",
diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts
index c21e7566c..abe2599f1 100644
--- a/backend/src/config/index.ts
+++ b/backend/src/config/index.ts
@@ -12,7 +12,7 @@ Decimal.set({
})
const constants = {
- DB_VERSION: '0066-x-community-sendcoins-transactions_table',
+ DB_VERSION: '0067-private_key_in_community_table',
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
LOG4JS_CONFIG: 'log4js-config.json',
// default log level on production should be info
diff --git a/backend/src/emails/__snapshots__/sendEmailVariants.test.ts.snap b/backend/src/emails/__snapshots__/sendEmailVariants.test.ts.snap
new file mode 100644
index 000000000..5a443b2bf
--- /dev/null
+++ b/backend/src/emails/__snapshots__/sendEmailVariants.test.ts.snap
@@ -0,0 +1,1521 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`sendEmailVariants sendAccountActivationEmail result has the correct html as snapshot 1`] = `
+"
+
+
+
+
+
+
+
+
+
+
+
+
Email Verification
+
+
Hello Peter Lustig,
+
Your email address has just been registered with Gradido.
+
+
+
Complete registration
+
Please click here to complete the registration and activate your Gradido account.
Activate account
+
Or copy the link into your browser window.
http://localhost/checkEmail/6627633878930542284
+
+ Request new valid link
+ 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.
New link
+
+
+
+
Kind regards,
your Gradido team
+
+
+
+
+
+
+"
+`;
+
+exports[`sendEmailVariants sendAccountMultiRegistrationEmail calls "sendEmailTranslated" result has the correct html as snapshot 1`] = `
+"
+
+
+
+
+
+
+
+
+
+
+
+
Try To Register Again With Your Email
+
+
Hello Peter Lustig,
+
Your email address has just been used again to register an account with Gradido.
However, an account already exists for your email address.
+
+
+
+
Reset password
+
If you have forgotten your password, please click here.
reset
+
Or copy the link into your browser window.
http://localhost/forgot-password
+
Contact support
+
If you did not try to register again, please contact our support:
support@supportmail.com
+
+
+
Kind regards,
your Gradido team
+
+
+
+
+
+
+"
+`;
+
+exports[`sendEmailVariants sendAddedContributionMessageEmail result has the correct html as snapshot 1`] = `
+"
+
+
+
+
+
+
+
+
+
+
+
+
Message about your common good contribution
+
+
Hello Peter Lustig,
+
You have received a message from Bibi Bloxberg regarding your common good contribution “My contribution.”.
+
+
+
Read and reply to message
+
To view and reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.
To account
+
Please do not reply to this email.
+
+
+
Kind regards,
your Gradido team
+
+
+
+
+
+
+"
+`;
+
+exports[`sendEmailVariants sendContributionConfirmedEmail result has the correct html as snapshot 1`] = `
+"
+
+
+
+
+
+
+
+
+
+
+
+
Your contribution to the common good was confirmed
+
+
Hello Peter Lustig,
+
Your common good contribution “My contribution.” has just been approved by Bibi Bloxberg. Your Gradido account has been credited with 23.54 GDD.
+
+
+
Contribution details
+
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.
To account
+
Or copy the link into your browser window.
https://gdd.gradido.net/community/contributions
+
Please do not reply to this email.
+
+
+
Kind regards,
your Gradido team
+
+
+
+
+
+
+"
+`;
+
+exports[`sendEmailVariants sendContributionDeletedEmail result has the correct html as snapshot 1`] = `
+"
+
+
+
+
+
+
+
+
+
+
+
+
Your common good contribution was deleted
+
+
Hello Peter Lustig,
+
Your common good contribution “My contribution.” was deleted by Bibi Bloxberg.
+
+
+
Contribution details
+
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.
To account
+
Or copy the link into your browser window.
https://gdd.gradido.net/community/contributions
+
Please do not reply to this email.
+
+
+
Kind regards,
your Gradido team
+
+
+
+
+
+
+"
+`;
+
+exports[`sendEmailVariants sendContributionDeniedEmail result has the correct html as snapshot 1`] = `
+"
+
+
+
+
+
+
+
+
+
+
+
+
Your common good contribution was rejected
+
+
Hello Peter Lustig,
+
Your common good contribution “My contribution.” was rejected by Bibi Bloxberg.
+
+
+
Contribution details
+
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.
To account
+
Or copy the link into your browser window.
https://gdd.gradido.net/community/contributions
+
Please do not reply to this email.
+
+
+
Kind regards,
your Gradido team
+
+
+
+
+
+
+"
+`;
+
+exports[`sendEmailVariants sendResetPasswordEmail result has the correct html as snapshot 1`] = `
+"
+
+
+
+
+
+
+
+
+
+
+
+
Reset password
+
+
Hello Peter Lustig,
+
You, or someone else, requested a password reset for this account.
+
+
+
Reset password
+
If it was you, please click here.
reset
+
Or copy the link into your browser window.
http://localhost/reset-password/3762660021544901417
+
+ Request new valid link
+ 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.
New link
+
+
+
+
Kind regards,
your Gradido team
+
+
+
+
+
+
+"
+`;
+
+exports[`sendEmailVariants sendTransactionLinkRedeemedEmail result has the correct html as snapshot 1`] = `
+"
+
+
+
+
+
+
+
+
+
+
+
+
Bibi Bloxberg has redeemed your Gradido link
+
+
Hello Peter Lustig,
+
Bibi Bloxberg (bibi@bloxberg.de) has just redeemed your link.
+
+
+
Transaction details
+
Amount: 17.65 GDD
Message: You deserve it! 🙏🏼
You can find transaction details in your Gradido account.
+
To account
+
Please do not reply to this email.
+
+
+
Kind regards,
your Gradido team
+
+
+
+
+
+
+"
+`;
+
+exports[`sendEmailVariants sendTransactionReceivedEmail result has the correct html as snapshot 1`] = `
+"
+
+
+
+
+
+
+
+
+
+
+
+
Bibi Bloxberg has sent you 37.40 Gradido
+
+
Hello Peter Lustig,
+
You have just received 37.40 GDD from Bibi Bloxberg (bibi@bloxberg.de).
+
+
+
Transaction details
+
You can find transaction details in your Gradido account.
To account
+
Please do not reply to this email.
+
+
+
Kind regards,
your Gradido team
+
+
+
+
+
+
+"
+`;
diff --git a/backend/src/emails/sendEmailTranslated.test.ts b/backend/src/emails/sendEmailTranslated.test.ts
index 3f1dd1061..b6ec0fbb5 100644
--- a/backend/src/emails/sendEmailTranslated.test.ts
+++ b/backend/src/emails/sendEmailTranslated.test.ts
@@ -94,11 +94,11 @@ describe('sendEmailTranslated', () => {
originalMessage: expect.objectContaining({
to: 'receiver@mail.org',
cc: 'support@gradido.net',
- from: 'Gradido (do not answer) ',
- attachments: [],
- subject: 'Gradido: Try To Register Again With Your Email',
- html: expect.stringContaining('Gradido: Try To Register Again With Your Email'),
- text: expect.stringContaining('GRADIDO: TRY TO REGISTER AGAIN WITH YOUR EMAIL'),
+ from: 'Gradido (emails.general.doNotAnswer) ',
+ attachments: expect.any(Array),
+ subject: 'Try To Register Again With Your Email',
+ html: expect.stringContaining('Try To Register Again With Your Email'),
+ text: expect.stringContaining('TRY TO REGISTER AGAIN WITH YOUR EMAIL'),
}),
})
})
@@ -142,11 +142,11 @@ describe('sendEmailTranslated', () => {
originalMessage: expect.objectContaining({
to: CONFIG.EMAIL_TEST_RECEIVER,
cc: 'support@gradido.net',
- from: `Gradido (do not answer) <${CONFIG.EMAIL_SENDER}>`,
- attachments: [],
- subject: 'Gradido: Try To Register Again With Your Email',
- html: expect.stringContaining('Gradido: Try To Register Again With Your Email'),
- text: expect.stringContaining('GRADIDO: TRY TO REGISTER AGAIN WITH YOUR EMAIL'),
+ from: `Gradido (emails.general.doNotAnswer) <${CONFIG.EMAIL_SENDER}>`,
+ attachments: expect.any(Array),
+ subject: 'Try To Register Again With Your Email',
+ html: expect.stringContaining('Try To Register Again With Your Email'),
+ text: expect.stringContaining('TRY TO REGISTER AGAIN WITH YOUR EMAIL'),
}),
})
})
diff --git a/backend/src/emails/sendEmailTranslated.ts b/backend/src/emails/sendEmailTranslated.ts
index 879d17656..acef8a11f 100644
--- a/backend/src/emails/sendEmailTranslated.ts
+++ b/backend/src/emails/sendEmailTranslated.ts
@@ -70,7 +70,36 @@ export const sendEmailTranslated = async ({
const resultSend = await email
.send({
template: path.join(__dirname, 'templates', template),
- message: receiver,
+ message: {
+ ...receiver,
+ attachments: [
+ {
+ filename: 'gradido-header.jpeg',
+ path: path.join(__dirname, 'templates/includes/gradido-header.jpeg'),
+ cid: 'gradidoheader',
+ },
+ {
+ filename: 'facebook-icon.png',
+ path: path.join(__dirname, 'templates/includes/facebook-icon.png'),
+ cid: 'facebookicon',
+ },
+ {
+ filename: 'telegram-icon.png',
+ path: path.join(__dirname, 'templates/includes/telegram-icon.png'),
+ cid: 'telegramicon',
+ },
+ {
+ filename: 'twitter-icon.png',
+ path: path.join(__dirname, 'templates/includes/twitter-icon.png'),
+ cid: 'twittericon',
+ },
+ {
+ filename: 'youtube-icon.png',
+ path: path.join(__dirname, 'templates/includes/youtube-icon.png'),
+ cid: 'youtubeicon',
+ },
+ ],
+ },
locals, // the 'locale' in here seems not to be used by 'email-template', because it doesn't work if the language isn't set before by 'i18n.setLocale'
})
.catch((error: unknown) => {
diff --git a/backend/src/emails/sendEmailVariants.test.ts b/backend/src/emails/sendEmailVariants.test.ts
index 76e96f129..3340a361d 100644
--- a/backend/src/emails/sendEmailVariants.test.ts
+++ b/backend/src/emails/sendEmailVariants.test.ts
@@ -34,11 +34,9 @@ let testEnv: {
beforeAll(async () => {
testEnv = await testEnvironment(logger, localization)
con = testEnv.con
- // await cleanDB()
})
afterAll(async () => {
- // await cleanDB()
await con.close()
})
@@ -87,8 +85,10 @@ describe('sendEmailVariants', () => {
},
})
})
+ })
- it('has expected result', () => {
+ describe('result', () => {
+ it('is the expected object', () => {
expect(result).toMatchObject({
envelope: {
from: 'info@gradido.net',
@@ -97,37 +97,17 @@ describe('sendEmailVariants', () => {
message: expect.any(String),
originalMessage: expect.objectContaining({
to: 'Peter Lustig ',
- from: 'Gradido (do not answer) ',
- attachments: [],
- subject: 'Gradido: Message about your common good contribution',
+ from: 'Gradido (emails.general.doNotAnswer) ',
+ attachments: expect.any(Array),
+ subject: 'Message about your common good contribution',
html: expect.any(String),
- text: expect.stringContaining('GRADIDO: MESSAGE ABOUT YOUR COMMON GOOD CONTRIBUTION'),
+ text: expect.stringContaining('MESSAGE ABOUT YOUR COMMON GOOD CONTRIBUTION'),
}),
})
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain(
- 'Gradido: Message about your common good contribution',
- )
- expect(result.originalMessage.html).toContain(
- '>Gradido: Message about your common good contribution',
- )
- expect(result.originalMessage.html).toContain('Hello Peter Lustig')
- expect(result.originalMessage.html).toContain(
- 'you have received a message from Bibi Bloxberg regarding your common good contribution “My contribution.”.',
- )
- expect(result.originalMessage.html).toContain(
- 'To view and reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab!',
- )
- expect(result.originalMessage.html).toContain(
- `Link to your account: ${CONFIG.EMAIL_LINK_OVERVIEW}`,
- )
- expect(result.originalMessage.html).toContain('Please do not reply to this email!')
- expect(result.originalMessage.html).toContain('Kind regards,
your Gradido team')
- expect(result.originalMessage.html).toContain('—————')
- expect(result.originalMessage.html).toContain(
- '
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland
support@supportmail.com
http://localhost/',
- )
+ })
+
+ it('has the correct html as snapshot', () => {
+ expect(result.originalMessage.html).toMatchSnapshot()
})
})
})
@@ -163,8 +143,10 @@ describe('sendEmailVariants', () => {
},
})
})
+ })
- it('has expected result', () => {
+ describe('result', () => {
+ it('is the expected object', () => {
expect(result).toMatchObject({
envelope: {
from: 'info@gradido.net',
@@ -173,41 +155,17 @@ describe('sendEmailVariants', () => {
message: expect.any(String),
originalMessage: expect.objectContaining({
to: 'Peter Lustig ',
- from: 'Gradido (do not answer) ',
- attachments: [],
- subject: 'Gradido: Email Verification',
+ from: 'Gradido (emails.general.doNotAnswer) ',
+ attachments: expect.any(Array),
+ subject: 'Email Verification',
html: expect.any(String),
- text: expect.stringContaining('GRADIDO: EMAIL VERIFICATION'),
+ text: expect.stringContaining('EMAIL VERIFICATION'),
}),
})
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain('Gradido: Email Verification')
- expect(result.originalMessage.html).toContain('>Gradido: Email Verification')
- expect(result.originalMessage.html).toContain('Hello Peter Lustig')
- expect(result.originalMessage.html).toContain(
- 'Your email address has just been registered with Gradido.',
- )
- expect(result.originalMessage.html).toContain(
- 'Please click on this link to complete the registration and activate your Gradido account:',
- )
- expect(result.originalMessage.html).toContain(
- 'http://localhost/checkEmail/6627633878930542284',
- )
- expect(result.originalMessage.html).toContain(
- 'or copy the link above into your browser window.',
- )
- expect(result.originalMessage.html).toContain(
- '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:',
- )
- expect(result.originalMessage.html).toContain(
- `${CONFIG.EMAIL_LINK_FORGOTPASSWORD}`,
- )
- expect(result.originalMessage.html).toContain('Kind regards,
your Gradido team')
- expect(result.originalMessage.html).toContain('—————')
- expect(result.originalMessage.html).toContain(
- '
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland
support@supportmail.com
http://localhost/',
- )
+ })
+
+ it('has the correct html as snapshot', () => {
+ expect(result.originalMessage.html).toMatchSnapshot()
})
})
})
@@ -240,54 +198,28 @@ describe('sendEmailVariants', () => {
})
})
- it('has expected result', () => {
- expect(result).toMatchObject({
- envelope: {
- from: 'info@gradido.net',
- to: ['peter@lustig.de'],
- },
- message: expect.any(String),
- originalMessage: expect.objectContaining({
- to: 'Peter Lustig ',
- from: 'Gradido (do not answer) ',
- attachments: [],
- subject: 'Gradido: Try To Register Again With Your Email',
- html: expect.any(String),
- text: expect.stringContaining('GRADIDO: TRY TO REGISTER AGAIN WITH YOUR EMAIL'),
- }),
+ describe('result', () => {
+ it('is the expected object', () => {
+ expect(result).toMatchObject({
+ envelope: {
+ from: 'info@gradido.net',
+ to: ['peter@lustig.de'],
+ },
+ message: expect.any(String),
+ originalMessage: expect.objectContaining({
+ to: 'Peter Lustig ',
+ from: 'Gradido (emails.general.doNotAnswer) ',
+ 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()
})
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain(
- 'Gradido: Try To Register Again With Your Email',
- )
- expect(result.originalMessage.html).toContain(
- '>Gradido: Try To Register Again With Your Email',
- )
- expect(result.originalMessage.html).toContain('Hello Peter Lustig')
- expect(result.originalMessage.html).toContain(
- 'Your email address has just been used again to register an account with Gradido.',
- )
- expect(result.originalMessage.html).toContain(
- 'However, an account already exists for your email address.',
- )
- expect(result.originalMessage.html).toContain(
- 'Please click on the following link if you have forgotten your password:',
- )
- expect(result.originalMessage.html).toContain(
- `${CONFIG.EMAIL_LINK_FORGOTPASSWORD}`,
- )
- expect(result.originalMessage.html).toContain(
- 'or copy the link above into your browser window.',
- )
- expect(result.originalMessage.html).toContain(
- 'If you are not the one who tried to register again, please contact our support:
support@supportmail.com',
- )
- expect(result.originalMessage.html).toContain('Kind regards,
your Gradido team')
- expect(result.originalMessage.html).toContain('—————')
- expect(result.originalMessage.html).toContain(
- '
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland
support@supportmail.com
http://localhost/',
- )
})
})
})
@@ -327,8 +259,10 @@ describe('sendEmailVariants', () => {
},
})
})
+ })
- it('has expected result', () => {
+ describe('result', () => {
+ it('is the expected object', () => {
expect(result).toMatchObject({
envelope: {
from: 'info@gradido.net',
@@ -337,37 +271,17 @@ describe('sendEmailVariants', () => {
message: expect.any(String),
originalMessage: expect.objectContaining({
to: 'Peter Lustig ',
- from: 'Gradido (do not answer) ',
- attachments: [],
- subject: 'Gradido: Your contribution to the common good was confirmed',
+ from: 'Gradido (emails.general.doNotAnswer) ',
+ attachments: expect.any(Array),
+ subject: 'Your contribution to the common good was confirmed',
html: expect.any(String),
- text: expect.stringContaining(
- 'GRADIDO: YOUR CONTRIBUTION TO THE COMMON GOOD WAS CONFIRMED',
- ),
+ text: expect.stringContaining('YOUR CONTRIBUTION TO THE COMMON GOOD WAS CONFIRMED'),
}),
})
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain(
- 'Gradido: Your contribution to the common good was confirmed',
- )
- expect(result.originalMessage.html).toContain(
- '>Gradido: Your contribution to the common good was confirmed',
- )
- expect(result.originalMessage.html).toContain('Hello Peter Lustig')
- expect(result.originalMessage.html).toContain(
- 'Your public good contribution “My contribution.” has just been confirmed by Bibi Bloxberg and credited to your Gradido account.',
- )
- expect(result.originalMessage.html).toContain('Amount: 23.54 GDD')
- expect(result.originalMessage.html).toContain(
- `Link to your account: ${CONFIG.EMAIL_LINK_OVERVIEW}`,
- )
- expect(result.originalMessage.html).toContain('Please do not reply to this email!')
- expect(result.originalMessage.html).toContain('Kind regards,
your Gradido team')
- expect(result.originalMessage.html).toContain('—————')
- expect(result.originalMessage.html).toContain(
- '
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland
support@supportmail.com
http://localhost/',
- )
+ })
+
+ it('has the correct html as snapshot', () => {
+ expect(result.originalMessage.html).toMatchSnapshot()
})
})
})
@@ -405,7 +319,9 @@ describe('sendEmailVariants', () => {
},
})
})
+ })
+ describe('result', () => {
it('has expected result', () => {
expect(result).toMatchObject({
envelope: {
@@ -415,37 +331,17 @@ describe('sendEmailVariants', () => {
message: expect.any(String),
originalMessage: expect.objectContaining({
to: 'Peter Lustig ',
- from: 'Gradido (do not answer) ',
- attachments: [],
- subject: 'Gradido: Your common good contribution was rejected',
+ from: 'Gradido (emails.general.doNotAnswer) ',
+ attachments: expect.any(Array),
+ subject: 'Your common good contribution was rejected',
html: expect.any(String),
- text: expect.stringContaining('GRADIDO: YOUR COMMON GOOD CONTRIBUTION WAS REJECTED'),
+ text: expect.stringContaining('YOUR COMMON GOOD CONTRIBUTION WAS REJECTED'),
}),
})
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain(
- 'Gradido: Your common good contribution was rejected',
- )
- expect(result.originalMessage.html).toContain(
- '>Gradido: Your common good contribution was rejected',
- )
- expect(result.originalMessage.html).toContain('Hello Peter Lustig')
- expect(result.originalMessage.html).toContain(
- 'Your public good contribution “My contribution.” was rejected by Bibi Bloxberg.',
- )
- expect(result.originalMessage.html).toContain(
- '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!',
- )
- expect(result.originalMessage.html).toContain(
- `Link to your account: ${CONFIG.EMAIL_LINK_OVERVIEW}`,
- )
- expect(result.originalMessage.html).toContain('Please do not reply to this email!')
- expect(result.originalMessage.html).toContain('Kind regards,
your Gradido team')
- expect(result.originalMessage.html).toContain('—————')
- expect(result.originalMessage.html).toContain(
- '
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland
support@supportmail.com
http://localhost/',
- )
+ })
+
+ it('has the correct html as snapshot', () => {
+ expect(result.originalMessage.html).toMatchSnapshot()
})
})
})
@@ -483,8 +379,10 @@ describe('sendEmailVariants', () => {
},
})
})
+ })
- it('has expected result', () => {
+ describe('result', () => {
+ it('is the expected object', () => {
expect(result).toMatchObject({
envelope: {
from: 'info@gradido.net',
@@ -493,37 +391,17 @@ describe('sendEmailVariants', () => {
message: expect.any(String),
originalMessage: expect.objectContaining({
to: 'Peter Lustig ',
- from: 'Gradido (do not answer) ',
- attachments: [],
- subject: 'Gradido: Your common good contribution was deleted',
+ from: 'Gradido (emails.general.doNotAnswer) ',
+ attachments: expect.any(Array),
+ subject: 'Your common good contribution was deleted',
html: expect.any(String),
- text: expect.stringContaining('GRADIDO: YOUR COMMON GOOD CONTRIBUTION WAS DELETED'),
+ text: expect.stringContaining('YOUR COMMON GOOD CONTRIBUTION WAS DELETED'),
}),
})
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain(
- 'Gradido: Your common good contribution was deleted',
- )
- expect(result.originalMessage.html).toContain(
- '>Gradido: Your common good contribution was deleted',
- )
- expect(result.originalMessage.html).toContain('Hello Peter Lustig')
- expect(result.originalMessage.html).toContain(
- 'Your public good contribution “My contribution.” was deleted by Bibi Bloxberg.',
- )
- expect(result.originalMessage.html).toContain(
- '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!',
- )
- expect(result.originalMessage.html).toContain(
- `Link to your account: ${CONFIG.EMAIL_LINK_OVERVIEW}`,
- )
- expect(result.originalMessage.html).toContain('Please do not reply to this email!')
- expect(result.originalMessage.html).toContain('Kind regards,
your Gradido team')
- expect(result.originalMessage.html).toContain('—————')
- expect(result.originalMessage.html).toContain(
- '
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland
support@supportmail.com
http://localhost/',
- )
+ })
+
+ it('has the correct html as snapshot', () => {
+ expect(result.originalMessage.html).toMatchSnapshot()
})
})
})
@@ -559,8 +437,10 @@ describe('sendEmailVariants', () => {
},
})
})
+ })
- it('has expected result', () => {
+ describe('result', () => {
+ it('is the expected object', () => {
expect(result).toMatchObject({
envelope: {
from: 'info@gradido.net',
@@ -569,39 +449,17 @@ describe('sendEmailVariants', () => {
message: expect.any(String),
originalMessage: expect.objectContaining({
to: 'Peter Lustig ',
- from: 'Gradido (do not answer) ',
- attachments: [],
- subject: 'Gradido: Reset password',
+ from: 'Gradido (emails.general.doNotAnswer) ',
+ attachments: expect.any(Array),
+ subject: 'Reset password',
html: expect.any(String),
- text: expect.stringContaining('GRADIDO: RESET PASSWORD'),
+ text: expect.stringContaining('RESET PASSWORD'),
}),
})
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain('Gradido: Reset password')
- expect(result.originalMessage.html).toContain('>Gradido: Reset password')
- expect(result.originalMessage.html).toContain('Hello Peter Lustig')
- expect(result.originalMessage.html).toContain(
- 'You, or someone else, requested a password reset for this account.',
- )
- expect(result.originalMessage.html).toContain('If it was you, please click on the link:')
- expect(result.originalMessage.html).toContain(
- 'http://localhost/reset-password/3762660021544901417',
- )
- expect(result.originalMessage.html).toContain(
- 'or copy the link above into your browser window.',
- )
- expect(result.originalMessage.html).toContain(
- '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:',
- )
- expect(result.originalMessage.html).toContain(
- `${CONFIG.EMAIL_LINK_FORGOTPASSWORD}`,
- )
- expect(result.originalMessage.html).toContain('Kind regards,
your Gradido team')
- expect(result.originalMessage.html).toContain('—————')
- expect(result.originalMessage.html).toContain(
- '
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland
support@supportmail.com
http://localhost/',
- )
+ })
+
+ it('has the correct html as snapshot', () => {
+ expect(result.originalMessage.html).toMatchSnapshot()
})
})
})
@@ -643,8 +501,10 @@ describe('sendEmailVariants', () => {
},
})
})
+ })
- it('has expected result', () => {
+ describe('result', () => {
+ it('is the expected object', () => {
expect(result).toMatchObject({
envelope: {
from: 'info@gradido.net',
@@ -653,36 +513,17 @@ describe('sendEmailVariants', () => {
message: expect.any(String),
originalMessage: expect.objectContaining({
to: 'Peter Lustig ',
- from: 'Gradido (do not answer) ',
- attachments: [],
- subject: 'Gradido: Bibi Bloxberg has redeemed your Gradido link',
+ from: 'Gradido (emails.general.doNotAnswer) ',
+ 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'),
}),
})
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain(
- 'Gradido: Bibi Bloxberg has redeemed your Gradido link',
- )
- expect(result.originalMessage.html).toContain(
- '>Gradido: Bibi Bloxberg has redeemed your Gradido link',
- )
- expect(result.originalMessage.html).toContain('Hello Peter Lustig')
- expect(result.originalMessage.html).toContain(
- 'Bibi Bloxberg (bibi@bloxberg.de) has just redeemed your link.',
- )
- expect(result.originalMessage.html).toContain('Amount: 17.65 GDD')
- expect(result.originalMessage.html).toContain('Message: You deserve it! 🙏🏼')
- expect(result.originalMessage.html).toContain(
- `You can find transaction details in your Gradido account: ${CONFIG.EMAIL_LINK_OVERVIEW}`,
- )
- expect(result.originalMessage.html).toContain('Please do not reply to this email!')
- expect(result.originalMessage.html).toContain('Kind regards,
your Gradido team')
- expect(result.originalMessage.html).toContain('—————')
- expect(result.originalMessage.html).toContain(
- '
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland
support@supportmail.com
http://localhost/',
- )
+ })
+
+ it('has the correct html as snapshot', () => {
+ expect(result.originalMessage.html).toMatchSnapshot()
})
})
})
@@ -722,8 +563,10 @@ describe('sendEmailVariants', () => {
},
})
})
+ })
- it('has expected result', () => {
+ describe('result', () => {
+ it('is the expected object', () => {
expect(result).toMatchObject({
envelope: {
from: 'info@gradido.net',
@@ -732,34 +575,17 @@ describe('sendEmailVariants', () => {
message: expect.any(String),
originalMessage: expect.objectContaining({
to: 'Peter Lustig ',
- from: 'Gradido (do not answer) ',
- attachments: [],
- subject: 'Gradido: Bibi Bloxberg has sent you 37.40 Gradido',
+ from: 'Gradido (emails.general.doNotAnswer) ',
+ attachments: expect.any(Array),
+ subject: 'Bibi Bloxberg has sent you 37.40 Gradido',
html: expect.any(String),
- text: expect.stringContaining('GRADIDO: BIBI BLOXBERG HAS SENT YOU 37.40 GRADIDO'),
+ text: expect.stringContaining('BIBI BLOXBERG HAS SENT YOU 37.40 GRADIDO'),
}),
})
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain('')
- expect(result.originalMessage.html).toContain(
- 'Gradido: Bibi Bloxberg has sent you 37.40 Gradido',
- )
- expect(result.originalMessage.html).toContain(
- '>Gradido: Bibi Bloxberg has sent you 37.40 Gradido',
- )
- expect(result.originalMessage.html).toContain('Hello Peter Lustig')
- expect(result.originalMessage.html).toContain(
- 'You have just received 37.40 GDD from Bibi Bloxberg (bibi@bloxberg.de).',
- )
- expect(result.originalMessage.html).toContain(
- `You can find transaction details in your Gradido account: ${CONFIG.EMAIL_LINK_OVERVIEW}`,
- )
- expect(result.originalMessage.html).toContain('Please do not reply to this email!')
- expect(result.originalMessage.html).toContain('Kind regards,
your Gradido team')
- expect(result.originalMessage.html).toContain('—————')
- expect(result.originalMessage.html).toContain(
- '
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland
support@supportmail.com
http://localhost/',
- )
+ })
+
+ it('has the correct html as snapshot', () => {
+ expect(result.originalMessage.html).toMatchSnapshot()
})
})
})
diff --git a/backend/src/emails/templates/accountActivation/html.pug b/backend/src/emails/templates/accountActivation/html.pug
index 6075fa8a8..027dcbc63 100644
--- a/backend/src/emails/templates/accountActivation/html.pug
+++ b/backend/src/emails/templates/accountActivation/html.pug
@@ -1,20 +1,16 @@
-doctype html
-html(lang=locale)
- head
- title= t('emails.accountActivation.subject')
- body
- h1(style='margin-bottom: 24px;')= t('emails.accountActivation.subject')
- #container.col
- include ../hello.pug
- p= t('emails.accountActivation.emailRegistered')
- p
- = t('emails.accountActivation.pleaseClickLink')
- br
- a(href=activationLink) #{activationLink}
- br
- = t('emails.general.orCopyLink')
- p
- = t('emails.accountActivation.duration', { hours: timeDurationObject.hours, minutes: timeDurationObject.minutes })
- br
- a(href=resendLink) #{resendLink}
- include ../greatingFormularImprint.pug
+extend ../layout.pug
+
+block content
+ h2= t('emails.accountActivation.title')
+ .text-block
+ include ../includes/salutation.pug
+ p= t('emails.accountActivation.emailRegistered')
+ .content
+ h2= t('emails.general.completeRegistration')
+ div(class="p_content")= t('emails.accountActivation.pleaseClickLink')
+ a.button-3(href=activationLink) #{t('emails.accountActivation.activateAccount')}
+ div(class="p_content")= t('emails.general.orCopyLink')
+
+ a.clink(href=activationLink) #{activationLink}
+
+ include ../includes/requestNewLink.pug
diff --git a/backend/src/emails/templates/accountMultiRegistration/html.pug b/backend/src/emails/templates/accountMultiRegistration/html.pug
index f8570422c..4d568261b 100644
--- a/backend/src/emails/templates/accountMultiRegistration/html.pug
+++ b/backend/src/emails/templates/accountMultiRegistration/html.pug
@@ -1,23 +1,22 @@
-doctype html
-html(lang=locale)
- head
- title= t('emails.accountMultiRegistration.subject')
- body
- h1(style='margin-bottom: 24px;')= t('emails.accountMultiRegistration.subject')
- #container.col
- include ../hello.pug
- p
- = t('emails.accountMultiRegistration.emailReused')
- br
- = t('emails.accountMultiRegistration.emailExists')
- p
- = t('emails.accountMultiRegistration.onForgottenPasswordClickLink')
- br
- a(href=resendLink) #{resendLink}
- br
- = t('emails.accountMultiRegistration.onForgottenPasswordCopyLink')
- p
- = t('emails.accountMultiRegistration.ifYouAreNotTheOne')
- br
- a(href='mailto:' + supportEmail)= supportEmail
- include ../greatingFormularImprint.pug
+extend ../layout.pug
+
+block content
+ h2= t('emails.accountMultiRegistration.title')
+ .text-block
+ include ../includes/salutation.pug
+ p
+ = t('emails.accountMultiRegistration.emailReused')
+ br
+ = t('emails.accountMultiRegistration.emailExists')
+ .content
+ h2= t('emails.resetPassword.title')
+ div(class="p_content")= t('emails.accountMultiRegistration.onForgottenPasswordClickLink')
+ a.button-3(href=resendLink) #{t('emails.general.reset')}
+ div(class="p_content")= t('emails.general.orCopyLink')
+
+ a.clink(href=resendLink) #{resendLink}
+
+ h2(style="color: red")= t('emails.accountMultiRegistration.contactSupport')
+ div(class="p_content")= t('emails.accountMultiRegistration.ifYouAreNotTheOne')
+
+ a.clink(href='mailto:' + supportEmail)= supportEmail
diff --git a/backend/src/emails/templates/addedContributionMessage/html.pug b/backend/src/emails/templates/addedContributionMessage/html.pug
index e7410c0f0..b09d2c0f0 100644
--- a/backend/src/emails/templates/addedContributionMessage/html.pug
+++ b/backend/src/emails/templates/addedContributionMessage/html.pug
@@ -1,16 +1,14 @@
-doctype html
-html(lang=locale)
- head
- title= t('emails.addedContributionMessage.subject')
- body
- h1(style='margin-bottom: 24px;')= t('emails.addedContributionMessage.subject')
- #container.col
- include ../hello.pug
- p= t('emails.addedContributionMessage.commonGoodContributionMessage', { senderFirstName, senderLastName, contributionMemo })
- p= t('emails.addedContributionMessage.toSeeAndAnswerMessage')
- p
- = t('emails.general.linkToYourAccount')
- = " "
- a(href=overviewURL) #{overviewURL}
- p= t('emails.general.pleaseDoNotReply')
- include ../greatingFormularImprint.pug
+extend ../layout.pug
+
+block content
+ h2= t('emails.addedContributionMessage.title')
+ .text-block
+ include ../includes/salutation.pug
+ p= t('emails.addedContributionMessage.commonGoodContributionMessage', { senderFirstName, senderLastName, contributionMemo })
+ .content
+ h2= t('emails.addedContributionMessage.readMessage')
+ div(class="p_content")= t('emails.addedContributionMessage.toSeeAndAnswerMessage')
+
+ a.button-3(href="https://gdd.gradido.net/community/contribution") #{t('emails.general.toAccount')}
+
+ include ../includes/doNotReply.pug
diff --git a/backend/src/emails/templates/contributionConfirmed/html.pug b/backend/src/emails/templates/contributionConfirmed/html.pug
index 4ff17ffd4..310993d97 100644
--- a/backend/src/emails/templates/contributionConfirmed/html.pug
+++ b/backend/src/emails/templates/contributionConfirmed/html.pug
@@ -1,16 +1,10 @@
-doctype html
-html(lang=locale)
- head
- title= t('emails.contributionConfirmed.subject')
- body
- h1(style='margin-bottom: 24px;')= t('emails.contributionConfirmed.subject')
- #container.col
- include ../hello.pug
- p= t('emails.contributionConfirmed.commonGoodContributionConfirmed', { senderFirstName, senderLastName, contributionMemo })
- p= t('emails.general.amountGDD', { amountGDD: contributionAmount })
- p
- = t('emails.general.linkToYourAccount')
- = " "
- a(href=overviewURL) #{overviewURL}
- p= t('emails.general.pleaseDoNotReply')
- include ../greatingFormularImprint.pug
+extend ../layout.pug
+
+block content
+ h2= t('emails.contributionConfirmed.title')
+ .text-block
+ include ../includes/salutation.pug
+ p= t('emails.contributionConfirmed.commonGoodContributionConfirmed', { contributionMemo, senderFirstName, senderLastName, amountGDD: contributionAmount })
+ .content
+ include ../includes/contributionDetailsCTA.pug
+ include ../includes/doNotReply.pug
\ No newline at end of file
diff --git a/backend/src/emails/templates/contributionDeleted/html.pug b/backend/src/emails/templates/contributionDeleted/html.pug
index d6b3ea207..daf54227d 100644
--- a/backend/src/emails/templates/contributionDeleted/html.pug
+++ b/backend/src/emails/templates/contributionDeleted/html.pug
@@ -1,16 +1,10 @@
-doctype html
-html(lang=locale)
- head
- title= t('emails.contributionDeleted.subject')
- body
- h1(style='margin-bottom: 24px;')= t('emails.contributionDeleted.subject')
- #container.col
- include ../hello.pug
- p= t('emails.contributionDeleted.commonGoodContributionDeleted', { senderFirstName, senderLastName, contributionMemo })
- p= t('emails.contributionDeleted.toSeeContributionsAndMessages')
- p
- = t('emails.general.linkToYourAccount')
- = " "
- a(href=overviewURL) #{overviewURL}
- p= t('emails.general.pleaseDoNotReply')
- include ../greatingFormularImprint.pug
+extend ../layout.pug
+
+block content
+ h2= t('emails.contributionDeleted.title')
+ .text-block
+ include ../includes/salutation.pug
+ p= t('emails.contributionDeleted.commonGoodContributionDeleted', { contributionMemo, senderFirstName, senderLastName })
+ .content
+ include ../includes/contributionDetailsCTA.pug
+ include ../includes/doNotReply.pug
diff --git a/backend/src/emails/templates/contributionDenied/html.pug b/backend/src/emails/templates/contributionDenied/html.pug
index a324374a7..d30653acd 100644
--- a/backend/src/emails/templates/contributionDenied/html.pug
+++ b/backend/src/emails/templates/contributionDenied/html.pug
@@ -1,16 +1,10 @@
-doctype html
-html(lang=locale)
- head
- title= t('emails.contributionDenied.subject')
- body
- h1(style='margin-bottom: 24px;')= t('emails.contributionDenied.subject')
- #container.col
- include ../hello.pug
- p= t('emails.contributionDenied.commonGoodContributionDenied', { senderFirstName, senderLastName, contributionMemo })
- p= t('emails.contributionDenied.toSeeContributionsAndMessages')
- p
- = t('emails.general.linkToYourAccount')
- = " "
- a(href=overviewURL) #{overviewURL}
- p= t('emails.general.pleaseDoNotReply')
- include ../greatingFormularImprint.pug
+extend ../layout.pug
+
+block content
+ h2= t('emails.contributionDenied.title')
+ .text-block
+ include ../includes/salutation.pug
+ p= t('emails.contributionDenied.commonGoodContributionDenied', { contributionMemo, senderFirstName, senderLastName })
+ .content
+ include ../includes/contributionDetailsCTA.pug
+ include ../includes/doNotReply.pug
diff --git a/backend/src/emails/templates/greatingFormularImprint.pug b/backend/src/emails/templates/greatingFormularImprint.pug
deleted file mode 100644
index d7d8c3a14..000000000
--- a/backend/src/emails/templates/greatingFormularImprint.pug
+++ /dev/null
@@ -1,16 +0,0 @@
-p(style='margin-top: 24px;')
- = t('emails.general.sincerelyYours')
- br
- = t('emails.general.yourGradidoTeam')
-p(style='margin-top: 24px;')= '—————'
-p(style='margin-top: 24px;')
- if t('general.imprintImageURL').length > 0
- div(style='position: relative; left: -22px;')
- img(src=t('general.imprintImageURL'), width='200', alt=t('general.imprintImageAlt'))
- br
- each line in t('general.imprint').split(/\n/)
- = line
- br
- a(href='mailto:' + supportEmail)= supportEmail
- br
- a(href=communityURL)= communityURL
diff --git a/backend/src/emails/templates/includes/contributionDetailsCTA.pug b/backend/src/emails/templates/includes/contributionDetailsCTA.pug
new file mode 100644
index 000000000..c2209014f
--- /dev/null
+++ b/backend/src/emails/templates/includes/contributionDetailsCTA.pug
@@ -0,0 +1,7 @@
+//-
+h2= t('emails.general.contributionDetails')
+div(class="p_content")= t('emails.contribution.toSeeContributionsAndMessages')
+a.button-3(href="https://gdd.gradido.net/community/contributions") #{t('emails.general.toAccount')}
+div(class="p_content")= t('emails.general.orCopyLink')
+
+a.clink(href="https://gdd.gradido.net/community/contributions") https://gdd.gradido.net/community/contributions
\ No newline at end of file
diff --git a/backend/src/emails/templates/includes/doNotReply.pug b/backend/src/emails/templates/includes/doNotReply.pug
new file mode 100644
index 000000000..506a5d0db
--- /dev/null
+++ b/backend/src/emails/templates/includes/doNotReply.pug
@@ -0,0 +1 @@
+div(class="p_content")= t('emails.general.pleaseDoNotReply')
\ No newline at end of file
diff --git a/backend/src/emails/templates/includes/email.css b/backend/src/emails/templates/includes/email.css
new file mode 100644
index 000000000..5110c3882
--- /dev/null
+++ b/backend/src/emails/templates/includes/email.css
@@ -0,0 +1,216 @@
+/* vietnamese */
+/* @font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 100;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
+} */
+/* latin-ext */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 100;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 100;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* vietnamese */
+/* @font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 200;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
+} */
+/* latin-ext */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 200;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 200;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* vietnamese */
+/* @font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 300;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
+} */
+/* latin-ext */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 300;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 300;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* vietnamese */
+/* @font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 400;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
+} */
+/* latin-ext */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 400;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 400;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* vietnamese */
+/* @font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 500;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
+} */
+/* latin-ext */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 500;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 500;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* vietnamese */
+/* @font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 600;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
+} */
+/* latin-ext */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 600;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 600;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* vietnamese */
+/* @font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 700;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
+} */
+/* latin-ext */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 700;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 700;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* vietnamese */
+/* @font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 800;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
+} */
+/* latin-ext */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 800;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 800;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* vietnamese */
+/* @font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 900;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
+} */
+/* latin-ext */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 900;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Work Sans';
+ font-style: normal;
+ font-weight: 900;
+ src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
diff --git a/backend/src/emails/templates/includes/facebook-icon.png b/backend/src/emails/templates/includes/facebook-icon.png
new file mode 100644
index 000000000..1d880cf3e
Binary files /dev/null and b/backend/src/emails/templates/includes/facebook-icon.png differ
diff --git a/backend/src/emails/templates/includes/footer.pug b/backend/src/emails/templates/includes/footer.pug
new file mode 100644
index 000000000..3ae63e32e
--- /dev/null
+++ b/backend/src/emails/templates/includes/footer.pug
@@ -0,0 +1,73 @@
+footer
+ .w-container(class="footer_01")
+ .socialmedia
+ a.slink(
+ target="_blank"
+ href="https://www.facebook.com/groups/Gradido/"
+ )
+ img.bi-facebook(
+ alt="facebook"
+ loading="lazy"
+ src="cid:facebookicon"
+ )
+ a.slink(
+ target="_blank"
+ href="https://t.me/GradidoGruppe"
+ )
+ img.bi-telegram(
+ alt="Telegram"
+ loading="lazy"
+ src="cid:telegramicon"
+ )
+ a.slink(
+ target="_blank"
+ href="https://twitter.com/gradido"
+ )
+ img.bi-twitter(
+ alt="Twitter"
+ loading="lazy"
+ src="cid:twittericon"
+ )
+ a.slink(
+ target="_blank"
+ href="https://www.youtube.com/c/GradidoNet"
+ )
+ img.bi-youtube(
+ alt="youtube"
+ loading="lazy"
+ src="cid:youtubeicon"
+ )
+ .line
+ .footer
+ div(class="footer_p1")= t("emails.footer.contactOurSupport")
+ div(class="footer_p2")= t("emails.footer.supportEmail")
+ img.image(
+ alt="Gradido Logo"
+ src="https://gdd.gradido.net/img/brand/green.png"
+ )
+ div
+ a(
+ class="terms_of_use"
+ href="https://gradido.net/de/impressum/"
+ target="_blank"
+ )= t("emails.footer.imprint")
+ br
+ a(
+ class="terms_of_use"
+ href="https://gradido.net/de/datenschutz/"
+ target="_blank"
+ )= t("emails.footer.privacyPolicy")
+ div(class="footer_p1")
+ | Gradido-Akademie
+ br
+ | Institut für Wirtschaftsbionik
+ br
+ | Pfarrweg 2
+ br
+ | 74653 Künzelsau
+ br
+ | Deutschland
+ br
+ br
+ br
+
diff --git a/backend/src/emails/templates/includes/gradido-header.jpeg b/backend/src/emails/templates/includes/gradido-header.jpeg
new file mode 100644
index 000000000..38a5c3a80
Binary files /dev/null and b/backend/src/emails/templates/includes/gradido-header.jpeg differ
diff --git a/backend/src/emails/templates/includes/greeting.pug b/backend/src/emails/templates/includes/greeting.pug
new file mode 100644
index 000000000..6693e23ca
--- /dev/null
+++ b/backend/src/emails/templates/includes/greeting.pug
@@ -0,0 +1,6 @@
+//- This sets the greeting at the end of every e-mail
+.text-block
+ p
+ = t('emails.general.sincerelyYours')
+ br
+ = t('emails.general.yourGradidoTeam')
\ No newline at end of file
diff --git a/backend/src/emails/templates/includes/header.pug b/backend/src/emails/templates/includes/header.pug
new file mode 100644
index 000000000..3160d3e2b
--- /dev/null
+++ b/backend/src/emails/templates/includes/header.pug
@@ -0,0 +1,13 @@
+header
+ .head
+ //- TODO
+ //- when https://gdd.gradido.net/img/gradido-email-header.jpg is on production,
+ //- replace this URL by https://gdd.gradido.net/img/brand/gradido-email-header.png
+ img.head-logo(
+ alt="Gradido Logo"
+ loading="lazy"
+ src="cid:gradidoheader"
+ )
+
+
+
diff --git a/backend/src/emails/templates/includes/requestNewLink.pug b/backend/src/emails/templates/includes/requestNewLink.pug
new file mode 100644
index 000000000..8baa3d6df
--- /dev/null
+++ b/backend/src/emails/templates/includes/requestNewLink.pug
@@ -0,0 +1,10 @@
+//-
+requestNewLink
+ h2= t('emails.general.requestNewLink')
+
+ if timeDurationObject.minutes == 0
+ div(class="p_content")= t('emails.general.linkValidity', { hours: timeDurationObject.hours })
+ else
+ div(class="p_content")= t('emails.general.linkValidityWithMinutes', { hours: timeDurationObject.hours, minutes: timeDurationObject.minutes })
+
+ a.button-4(href=resendLink) #{t('emails.general.newLink')}
\ No newline at end of file
diff --git a/backend/src/emails/templates/hello.pug b/backend/src/emails/templates/includes/salutation.pug
similarity index 100%
rename from backend/src/emails/templates/hello.pug
rename to backend/src/emails/templates/includes/salutation.pug
diff --git a/backend/src/emails/templates/includes/telegram-icon.png b/backend/src/emails/templates/includes/telegram-icon.png
new file mode 100644
index 000000000..4c36ff661
Binary files /dev/null and b/backend/src/emails/templates/includes/telegram-icon.png differ
diff --git a/backend/src/emails/templates/includes/twitter-icon.png b/backend/src/emails/templates/includes/twitter-icon.png
new file mode 100644
index 000000000..fffb9b599
Binary files /dev/null and b/backend/src/emails/templates/includes/twitter-icon.png differ
diff --git a/backend/src/emails/templates/includes/webflow.css b/backend/src/emails/templates/includes/webflow.css
new file mode 100644
index 000000000..02e7fc4e0
--- /dev/null
+++ b/backend/src/emails/templates/includes/webflow.css
@@ -0,0 +1,136 @@
+body{
+ 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;
+}
+
+h2 {
+ margin-top: 15px;
+ color: #383838;
+}
+
+.container {
+ max-width: 680px;
+ margin: 0 auto;
+ display: block;
+}
+
+.head-logo {
+ width: 100%;
+ height: auto;
+}
+
+.text-block {
+ margin-top: 20px;
+ color: #9ca0a8;
+}
+
+.content {
+ display: block;
+ width: 78%;
+ margin: 40px 1% 40px 1%;
+ padding: 20px 10% 40px 10%;
+ border-radius: 24px;
+ background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5);
+}
+
+.p_content{
+ margin: 15px 0 15px 0;
+ line-height: 26px;
+ color: #9ca0a8;
+}
+
+.clink {
+ line-break: anywhere;
+ margin-bottom: 40px;
+}
+
+.button-3,
+.button-4 {
+ 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%;
+}
+
+.button-4 {
+ background-image: radial-gradient(circle farthest-corner at 0% 0%, #616161, #c2c2c2);
+}
+
+.socialmedia {
+ display: flex;
+ margin-top: 40px;
+ max-width: 600px;
+
+}
+.slink{
+ width: 150px;
+}
+
+.footer {
+ padding-bottom: 20px;
+}
+
+.footer_p1 {
+ margin-top: 30px;
+ color: #9ca0a8;
+ margin-bottom: 30px;
+}
+
+.footer_p2 {
+ color: #383838;
+ font-weight: bold;
+}
+
+
+.image {
+ width: 200px;
+ margin-top: 30px;
+ margin-bottom: 30px;
+}
+
+.div-block {
+ display: table;
+ margin-top: 20px;
+ margin-bottom: 40px;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+}
+
+.terms_of_use {
+ color: #9ca0a8;
+}
+
+.text-block-3 {
+ color: #9ca0a8;
+ margin-bottom: 30px;
+}
+
+.line_image,
+.line {
+ width: 100%;
+ height: 13px;
+ margin-top: 40px;
+}
+
+.line_image {
+ background-image: linear-gradient(90deg, #c58d38, #c58d38 0%, #f3cd7c 35%, #dbb056 54%, #eec05f 63%, #cc9d3d);
+}
+
+.line {
+ background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d);
+}
diff --git a/backend/src/emails/templates/includes/youtube-icon.png b/backend/src/emails/templates/includes/youtube-icon.png
new file mode 100644
index 000000000..d135ba625
Binary files /dev/null and b/backend/src/emails/templates/includes/youtube-icon.png differ
diff --git a/backend/src/emails/templates/layout.pug b/backend/src/emails/templates/layout.pug
new file mode 100644
index 000000000..0995b2647
--- /dev/null
+++ b/backend/src/emails/templates/layout.pug
@@ -0,0 +1,26 @@
+doctype html
+html(lang=locale)
+ head
+ 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{outline:none;}
+ style
+ include includes/email.css
+ include includes/webflow.css
+
+ body
+ div.container
+ include includes/header.pug
+
+ .wrapper
+ block content
+ include includes/greeting.pug
+
+ include includes/footer.pug
diff --git a/backend/src/emails/templates/resetPassword/html.pug b/backend/src/emails/templates/resetPassword/html.pug
index 53ffbcd04..4d4ed3f50 100644
--- a/backend/src/emails/templates/resetPassword/html.pug
+++ b/backend/src/emails/templates/resetPassword/html.pug
@@ -1,20 +1,16 @@
-doctype html
-html(lang=locale)
- head
- title= t('emails.resetPassword.subject')
- body
- h1(style='margin-bottom: 24px;')= t('emails.resetPassword.subject')
- #container.col
- include ../hello.pug
- p= t('emails.resetPassword.youOrSomeoneResetPassword')
- p
- = t('emails.resetPassword.pleaseClickLink')
- br
- a(href=resetLink) #{resetLink}
- br
- = t('emails.general.orCopyLink')
- p
- = t('emails.resetPassword.duration', { hours: timeDurationObject.hours, minutes: timeDurationObject.minutes })
- br
- a(href=resendLink) #{resendLink}
- include ../greatingFormularImprint.pug
+extends ../layout.pug
+
+block content
+ h2= t('emails.resetPassword.title')
+ .text-block
+ include ../includes/salutation.pug
+ p= t('emails.resetPassword.youOrSomeoneResetPassword')
+ .content
+ h2= t('emails.resetPassword.title')
+ div(class="p_content")= t('emails.resetPassword.pleaseClickLink')
+ a.button-3(href=resetLink) #{t('emails.general.reset')}
+ div(class="p_content")= t('emails.general.orCopyLink')
+
+ a.clink(href=resetLink) #{resetLink}
+
+ include ../includes/requestNewLink.pug
diff --git a/backend/src/emails/templates/transactionLinkRedeemed/html.pug b/backend/src/emails/templates/transactionLinkRedeemed/html.pug
index 30146e27f..598a18337 100644
--- a/backend/src/emails/templates/transactionLinkRedeemed/html.pug
+++ b/backend/src/emails/templates/transactionLinkRedeemed/html.pug
@@ -1,19 +1,18 @@
-doctype html
-html(lang=locale)
- head
- title= t('emails.transactionLinkRedeemed.subject', { senderFirstName, senderLastName })
- body
- h1(style='margin-bottom: 24px;')= t('emails.transactionLinkRedeemed.subject', { senderFirstName, senderLastName })
- #container.col
- include ../hello.pug
- p= t('emails.transactionLinkRedeemed.hasRedeemedYourLink', { senderFirstName, senderLastName, senderEmail })
- p
- = t('emails.general.amountGDD', { amountGDD: transactionAmount })
- br
- = t('emails.transactionLinkRedeemed.memo', { transactionMemo })
- p
- = t('emails.general.detailsYouFindOnLinkToYourAccount')
- = " "
- a(href=overviewURL) #{overviewURL}
- p= t('emails.general.pleaseDoNotReply')
- include ../greatingFormularImprint.pug
+extend ../layout.pug
+
+block content
+ h2= t('emails.transactionLinkRedeemed.title', { senderFirstName, senderLastName })
+ .text-block
+ include ../includes/salutation.pug
+ p= t('emails.transactionLinkRedeemed.hasRedeemedYourLink', { senderFirstName, senderLastName, senderEmail })
+ .content
+ h2= t('emails.general.transactionDetails')
+ div(class="p_content")= t('emails.general.amountGDD', { amountGDD: transactionAmount })
+ br
+ = t('emails.transactionLinkRedeemed.memo', { transactionMemo })
+ br
+ = t('emails.general.detailsYouFindOnLinkToYourAccount')
+
+ a.button-3(href="https://gdd.gradido.net/transactions") #{t('emails.general.toAccount')}
+
+ include ../includes/doNotReply.pug
diff --git a/backend/src/emails/templates/transactionReceived/html.pug b/backend/src/emails/templates/transactionReceived/html.pug
index e6807f539..abf468dd0 100644
--- a/backend/src/emails/templates/transactionReceived/html.pug
+++ b/backend/src/emails/templates/transactionReceived/html.pug
@@ -1,15 +1,15 @@
-doctype html
-html(lang=locale)
- head
- title= t('emails.transactionReceived.subject', { senderFirstName, senderLastName, transactionAmount })
- body
- h1(style='margin-bottom: 24px;')= t('emails.transactionReceived.subject', { senderFirstName, senderLastName, transactionAmount })
- #container.col
- include ../hello.pug
- p= t('emails.transactionReceived.haveReceivedAmountGDDFrom', { transactionAmount, senderFirstName, senderLastName, senderEmail })
- p
- = t('emails.general.detailsYouFindOnLinkToYourAccount')
- = " "
- a(href=overviewURL) #{overviewURL}
- p= t('emails.general.pleaseDoNotReply')
- include ../greatingFormularImprint.pug
+extend ../layout.pug
+
+block content
+ h2= t('emails.transactionReceived.title', { senderFirstName, senderLastName, transactionAmount })
+ .text-block
+ include ../includes/salutation.pug
+ p= t('emails.transactionReceived.haveReceivedAmountGDDFrom', { transactionAmount, senderFirstName, senderLastName, senderEmail })
+ .content
+ h2= t('emails.general.transactionDetails')
+ div(class="p_content")= t('emails.general.detailsYouFindOnLinkToYourAccount')
+
+ a.button-3(href="https://gdd.gradido.net/transactions") #{t('emails.general.toAccount')}
+
+ include ../includes/doNotReply.pug
+
diff --git a/backend/src/graphql/arg/SearchUsersArgs.ts b/backend/src/graphql/arg/SearchUsersArgs.ts
deleted file mode 100644
index 0ebc442c3..000000000
--- a/backend/src/graphql/arg/SearchUsersArgs.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { ArgsType, Field, Int } from 'type-graphql'
-
-import { SearchUsersFilters } from '@arg/SearchUsersFilters'
-
-@ArgsType()
-export class SearchUsersArgs {
- @Field(() => String)
- searchText: string
-
- @Field(() => Int, { nullable: true })
- // eslint-disable-next-line type-graphql/invalid-nullable-input-type
- currentPage?: number
-
- @Field(() => Int, { nullable: true })
- // eslint-disable-next-line type-graphql/invalid-nullable-input-type
- pageSize?: number
-
- // eslint-disable-next-line type-graphql/wrong-decorator-signature
- @Field(() => SearchUsersFilters, { nullable: true, defaultValue: null })
- filters?: SearchUsersFilters | null
-}
diff --git a/backend/src/graphql/model/KlickTipp.ts b/backend/src/graphql/model/KlickTipp.ts
index 059c7874d..356ed391f 100644
--- a/backend/src/graphql/model/KlickTipp.ts
+++ b/backend/src/graphql/model/KlickTipp.ts
@@ -1,12 +1,9 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { ObjectType, Field } from 'type-graphql'
@ObjectType()
export class KlickTipp {
- constructor(json: any) {
- this.newsletterState = json.status === 'Subscribed'
+ constructor(newsletterState: boolean) {
+ this.newsletterState = newsletterState
}
@Field(() => Boolean)
diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts
index 25787490f..0384b64c5 100644
--- a/backend/src/graphql/resolver/UserResolver.test.ts
+++ b/backend/src/graphql/resolver/UserResolver.test.ts
@@ -2110,7 +2110,7 @@ describe('UserResolver', () => {
describe('search users', () => {
const variablesWithoutTextAndFilters = {
- searchText: '',
+ query: '',
currentPage: 1,
pageSize: 25,
filters: null,
diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts
index 9934c93de..9df6b861b 100644
--- a/backend/src/graphql/resolver/UserResolver.ts
+++ b/backend/src/graphql/resolver/UserResolver.ts
@@ -8,22 +8,12 @@ import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink'
import { User as DbUser } from '@entity/User'
import { UserContact as DbUserContact } from '@entity/UserContact'
import i18n from 'i18n'
-import {
- Resolver,
- Query,
- Args,
- Arg,
- Authorized,
- Ctx,
- UseMiddleware,
- Mutation,
- Int,
-} from 'type-graphql'
+import { Resolver, Query, Args, Arg, Authorized, Ctx, Mutation, Int } from 'type-graphql'
import { v4 as uuidv4 } from 'uuid'
import { CreateUserArgs } from '@arg/CreateUserArgs'
import { Paginated } from '@arg/Paginated'
-import { SearchUsersArgs } from '@arg/SearchUsersArgs'
+import { SearchUsersFilters } from '@arg/SearchUsersFilters'
import { UnsecureLoginArgs } from '@arg/UnsecureLoginArgs'
import { UpdateUserInfosArgs } from '@arg/UpdateUserInfosArgs'
import { OptInType } from '@enum/OptInType'
@@ -60,7 +50,6 @@ import {
EVENT_ADMIN_USER_DELETE,
EVENT_ADMIN_USER_UNDELETE,
} from '@/event/Events'
-import { klicktippNewsletterStateMiddleware } from '@/middleware/klicktippMiddleware'
import { isValidPassword } from '@/password/EncryptorUtils'
import { encryptPassword, verifyPassword } from '@/password/PasswordEncryptor'
import { Context, getUser, getClientTimezoneOffset } from '@/server/context'
@@ -71,15 +60,14 @@ import { hasElopageBuys } from '@/util/hasElopageBuys'
import { getTimeDurationObject, printTimeDuration } from '@/util/time'
import random from 'random-bigint'
+import { randombytes_random } from 'sodium-native'
import { FULL_CREATION_AVAILABLE } from './const/const'
import { getUserCreations } from './util/creations'
import { findUserByIdentifier } from './util/findUserByIdentifier'
+import { getKlicktippState } from './util/getKlicktippState'
import { validateAlias } from './util/validateAlias'
-// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-commonjs
-const sodium = require('sodium-native')
-
const LANGUAGES = ['de', 'en', 'es', 'fr', 'nl']
const DEFAULT_LANGUAGE = 'de'
const isLanguage = (language: string): boolean => {
@@ -122,7 +110,6 @@ const newGradidoID = async (): Promise => {
export class UserResolver {
@Authorized([RIGHTS.VERIFY_LOGIN])
@Query(() => User)
- @UseMiddleware(klicktippNewsletterStateMiddleware)
async verifyLogin(@Ctx() context: Context): Promise {
logger.info('verifyLogin...')
// TODO refactor and do not have duplicate code with login(see below)
@@ -132,12 +119,12 @@ export class UserResolver {
user.hasElopage = await this.hasElopage(context)
logger.debug(`verifyLogin... successful: ${user.firstName}.${user.lastName}`)
+ user.klickTipp = await getKlicktippState(userEntity.emailContact.email)
return user
}
@Authorized([RIGHTS.LOGIN])
@Mutation(() => User)
- @UseMiddleware(klicktippNewsletterStateMiddleware)
async login(
@Args() { email, password, publisherId }: UnsecureLoginArgs,
@Ctx() context: Context,
@@ -183,6 +170,7 @@ export class UserResolver {
dbUser.publisherId = publisherId
await DbUser.save(dbUser)
}
+ user.klickTipp = await getKlicktippState(dbUser.emailContact.email)
context.setHeaders.push({
key: 'token',
@@ -237,7 +225,7 @@ export class UserResolver {
// TODO: this is unsecure, but the current implementation of the login server. This way it can be queried if the user with given EMail is existent.
const user = new User(communityDbUser)
- user.id = sodium.randombytes_random() % (2048 * 16) // TODO: for a better faking derive id from email so that it will be always the same id when the same email comes in?
+ user.id = randombytes_random() % (2048 * 16) // TODO: for a better faking derive id from email so that it will be always the same id when the same email comes in?
user.gradidoID = uuidv4()
user.firstName = firstName
user.lastName = lastName
@@ -640,8 +628,11 @@ export class UserResolver {
@Authorized([RIGHTS.SEARCH_USERS])
@Query(() => SearchUsersResult)
async searchUsers(
+ @Arg('query', () => String) query: string,
+ @Arg('filters', () => SearchUsersFilters, { nullable: true })
+ filters: SearchUsersFilters | null | undefined,
@Args()
- { searchText, currentPage = 1, pageSize = 25, filters }: SearchUsersArgs,
+ { currentPage = 1, pageSize = 25, order = Order.ASC }: Paginated,
@Ctx() context: Context,
): Promise {
const clientTimezoneOffset = getClientTimezoneOffset(context)
@@ -659,15 +650,16 @@ export class UserResolver {
userFields.map((fieldName) => {
return 'user.' + fieldName
}),
- searchText,
+ query,
filters ?? null,
currentPage,
pageSize,
+ order,
)
if (users.length === 0) {
return {
- userCount: 0,
+ userCount: count,
userList: [],
}
}
diff --git a/backend/src/graphql/resolver/util/getKlicktippState.ts b/backend/src/graphql/resolver/util/getKlicktippState.ts
new file mode 100644
index 000000000..728f565ff
--- /dev/null
+++ b/backend/src/graphql/resolver/util/getKlicktippState.ts
@@ -0,0 +1,19 @@
+/* eslint-disable @typescript-eslint/no-unsafe-return */
+import { KlickTipp } from '@model/KlickTipp'
+
+import { getKlickTippUser } from '@/apis/KlicktippController'
+import { klickTippLogger as logger } from '@/server/logger'
+
+export const getKlicktippState = async (email: string): Promise => {
+ try {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+ const klickTippUser = await getKlickTippUser(email)
+ if (klickTippUser) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ return new KlickTipp(klickTippUser.status === 'Subscribed')
+ }
+ } catch (err) {
+ logger.error('There is no klicktipp user for email', email, err)
+ }
+ return new KlickTipp(false)
+}
diff --git a/backend/src/locales/de.json b/backend/src/locales/de.json
index 4dc90def2..349c5089e 100644
--- a/backend/src/locales/de.json
+++ b/backend/src/locales/de.json
@@ -1,69 +1,92 @@
{
"emails": {
"accountActivation": {
- "duration": "Der Link hat eine Gültigkeit von {hours} Stunden und {minutes} Minuten. Sollte die Gültigkeit des Links bereits abgelaufen sein, kannst du dir hier einen neuen Link schicken lassen:",
+ "activateAccount": "Konto aktivieren",
"emailRegistered": "deine E-Mail-Adresse wurde soeben bei Gradido registriert.",
- "pleaseClickLink": "Klicke bitte auf diesen Link, um die Registrierung abzuschließen und dein Gradido-Konto zu aktivieren:",
- "subject": "Gradido: E-Mail Überprüfung"
+ "pleaseClickLink": "Klicke bitte hier, um die Registrierung abzuschließen und dein Gradido-Konto zu aktivieren.",
+ "subject": "E-Mail Überprüfung",
+ "title": "E-Mail Überprüfung"
},
"accountMultiRegistration": {
+ "contactSupport": "Support kontaktieren",
"emailExists": "Es existiert jedoch zu deiner E-Mail-Adresse schon ein Konto.",
"emailReused": "deine E-Mail-Adresse wurde soeben erneut benutzt, um bei Gradido ein Konto zu registrieren.",
- "ifYouAreNotTheOne": "Wenn du nicht derjenige bist, der versucht hat sich erneut zu registrieren, wende dich bitte an unseren Support:",
- "onForgottenPasswordClickLink": "Klicke bitte auf den folgenden Link, falls du dein Passwort vergessen haben solltest:",
- "onForgottenPasswordCopyLink": "oder kopiere den obigen Link in dein Browserfenster.",
- "subject": "Gradido: Erneuter Registrierungsversuch mit deiner E-Mail"
+ "ifYouAreNotTheOne": "Wenn du nicht versucht hast dich erneut zu registrieren, wende dich bitte an unseren Support:",
+ "onForgottenPasswordClickLink": "Solltest du dein Passwort vergessen haben, klicke bitte hier.",
+ "subject": "Erneuter Registrierungsversuch mit deiner E-Mail",
+ "title": "Erneuter Registrierungsversuch mit deiner E-Mail"
},
"addedContributionMessage": {
"commonGoodContributionMessage": "du hast zu deinem Gemeinwohl-Beitrag „{contributionMemo}“ eine Nachricht von {senderFirstName} {senderLastName} erhalten.",
- "subject": "Gradido: Nachricht zu deinem Gemeinwohl-Beitrag",
- "toSeeAndAnswerMessage": "Um die Nachricht zu sehen und darauf zu antworten, gehe in deinem Gradido-Konto ins Menü „Schöpfen“ auf den Tab „Meine Beiträge“!"
+ "readMessage": "Nachricht lesen und beantworten",
+ "subject": "Nachricht zu deinem Gemeinwohl-Beitrag",
+ "title": "Nachricht zu deinem Gemeinwohl-Beitrag",
+ "toSeeAndAnswerMessage": "Um die Nachricht zu sehen und darauf zu antworten, gehe in deinem Gradido-Konto ins Menü „Schöpfen“ auf den Tab „Meine Beiträge“."
+ },
+ "contribution": {
+ "toSeeContributionsAndMessages": "Um deine Gemeinwohl-Beiträge und dazugehörige Nachrichten zu sehen, gehe in deinem Gradido-Konto ins Menü „Schöpfen“ auf den Tab „Meine Beiträge“."
},
"contributionConfirmed": {
- "commonGoodContributionConfirmed": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde soeben von {senderFirstName} {senderLastName} bestätigt und in deinem Gradido-Konto gutgeschrieben.",
- "subject": "Gradido: Dein Gemeinwohl-Beitrag wurde bestätigt"
+ "commonGoodContributionConfirmed": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde soeben von {senderFirstName} {senderLastName} bestätigt. Es wurden deinem Gradido-Konto {amountGDD} GDD gutgeschrieben.",
+ "subject": "Dein Gemeinwohl-Beitrag wurde bestätigt",
+ "title": "Dein Gemeinwohl-Beitrag wurde bestätigt"
},
"contributionDeleted": {
"commonGoodContributionDeleted": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde von {senderFirstName} {senderLastName} gelöscht.",
- "subject": "Gradido: Dein Gemeinwohl-Beitrag wurde gelöscht",
- "toSeeContributionsAndMessages": "Um deine Gemeinwohl-Beiträge und dazugehörige Nachrichten zu sehen, gehe in deinem Gradido-Konto ins Menü „Schöpfen“ auf den Tab „Meine Beiträge“!"
+ "subject": "Dein Gemeinwohl-Beitrag wurde gelöscht",
+ "title": "Dein Gemeinwohl-Beitrag wurde gelöscht"
},
"contributionDenied": {
"commonGoodContributionDenied": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde von {senderFirstName} {senderLastName} abgelehnt.",
- "subject": "Gradido: Dein Gemeinwohl-Beitrag wurde abgelehnt",
- "toSeeContributionsAndMessages": "Um deine Gemeinwohl-Beiträge und dazugehörige Nachrichten zu sehen, gehe in deinem Gradido-Konto ins Menü „Schöpfen“ auf den Tab „Meine Beiträge“!"
+ "subject": "Dein Gemeinwohl-Beitrag wurde abgelehnt",
+ "title": "Dein Gemeinwohl-Beitrag wurde abgelehnt"
+ },
+ "footer": {
+ "contactOurSupport": "Bei weiteren Fragen kontaktiere bitte unseren Support.",
+ "imprint": "Impressum",
+ "imprintAddress": "Gradido-Akademie\nInstitut für Wirtschaftsbionik\nPfarrweg 2\n74653 Künzelsau\nDeutschland",
+ "imprintImageAlt": "Gradido-Akademie Logo",
+ "privacyPolicy": "Datenschutzerklärung",
+ "supportEmail": "support@gradido.net"
},
"general": {
"amountGDD": "Betrag: {amountGDD} GDD",
- "detailsYouFindOnLinkToYourAccount": "Details zur Transaktion findest du in deinem Gradido-Konto:",
- "doNotAnswer": "nicht antworten",
+ "completeRegistration": "Registrierung abschließen",
+ "contribution": "Gemeinwohl-Beitrag: {contributionMemo}",
+ "contributionDetails": "Beitragsdetails",
+ "detailsYouFindOnLinkToYourAccount": "Details zur Transaktion findest du in deinem Gradido-Konto.",
"helloName": "Hallo {firstName} {lastName},",
- "linkToYourAccount": "Link zu deinem Konto:",
- "orCopyLink": "oder kopiere den obigen Link in dein Browserfenster.",
- "pleaseDoNotReply": "Bitte antworte nicht auf diese E-Mail!",
+ "linkValidity": "Der Link hat eine Gültigkeit von {hours} Stunden.\nSollte die Gültigkeit des Links bereits abgelaufen sein, kannst du dir hier einen neuen Link schicken lassen.",
+ "linkValidityWithMinutes": "Der Link hat eine Gültigkeit von {hours} Stunden und {minutes} Minuten.\nSollte die Gültigkeit des Links bereits abgelaufen sein, kannst du dir hier einen neuen Link schicken lassen.",
+ "newLink": "Neuer Link",
+ "orCopyLink": "Oder kopiere den Link in dein Browserfenster.",
+ "pleaseDoNotReply": "Bitte antworte nicht auf diese E-Mail.",
+ "requestNewLink": "Neuen gültigen Link anfordern",
+ "reset": "zurücksetzen",
"sincerelyYours": "Liebe Grüße",
+ "toAccount": "Zum Konto",
+ "transactionDetails": "Transaktionsdetails",
"yourGradidoTeam": "dein Gradido-Team"
},
"resetPassword": {
- "duration": "Der Link hat eine Gültigkeit von {hours} Stunden und {minutes} Minuten. Sollte die Gültigkeit des Links bereits abgelaufen sein, kannst du dir hier einen neuen Link schicken lassen:",
- "pleaseClickLink": "Wenn du es warst, klicke bitte auf den Link:",
- "subject": "Gradido: Passwort zurücksetzen",
- "youOrSomeoneResetPassword": "du, oder jemand anderes, hast für dieses Konto ein Zurücksetzen des Passworts angefordert."
+ "pleaseClickLink": "Wenn du es warst, klicke bitte hier.",
+ "subject": "Passwort zurücksetzen",
+ "title": "Passwort zurücksetzen",
+ "youOrSomeoneResetPassword": "du oder jemand anderes, hast für dieses Konto ein Zurücksetzen des Passworts angefordert."
},
"transactionLinkRedeemed": {
"hasRedeemedYourLink": "{senderFirstName} {senderLastName} ({senderEmail}) hat soeben deinen Link eingelöst.",
"memo": "Nachricht: {transactionMemo}",
- "subject": "Gradido: {senderFirstName} {senderLastName} hat deinen Gradido-Link eingelöst"
+ "subject": "{senderFirstName} {senderLastName} hat deinen Gradido-Link eingelöst",
+ "title": "{senderFirstName} {senderLastName} hat deinen Gradido-Link eingelöst"
},
"transactionReceived": {
"haveReceivedAmountGDDFrom": "du hast soeben {transactionAmount} GDD von {senderFirstName} {senderLastName} ({senderEmail}) erhalten.",
- "subject": "Gradido: {senderFirstName} {senderLastName} hat dir {transactionAmount} Gradido gesendet"
+ "subject": "{senderFirstName} {senderLastName} hat dir {transactionAmount} Gradido gesendet",
+ "title": "{senderFirstName} {senderLastName} hat dir {transactionAmount} Gradido gesendet"
}
},
"general": {
- "decimalSeparator": ",",
- "imprint": "Gradido-Akademie\nInstitut für Wirtschaftsbionik\nPfarrweg 2\n74653 Künzelsau\nDeutschland",
- "imprintImageAlt": "Gradido-Akademie Logo",
- "imprintImageURL": "https://gdd.gradido.net/img/brand/green.png"
+ "decimalSeparator": ","
}
}
diff --git a/backend/src/locales/en.json b/backend/src/locales/en.json
index 74c5739bc..cf4bbef47 100644
--- a/backend/src/locales/en.json
+++ b/backend/src/locales/en.json
@@ -1,69 +1,92 @@
{
"emails": {
"accountActivation": {
- "duration": "The link has a validity of {hours} hours and {minutes} minutes. If the validity of the link has already expired, you can have a new link sent to you here:",
+ "activateAccount": "Activate account",
"emailRegistered": "Your email address has just been registered with Gradido.",
- "pleaseClickLink": "Please click on this link to complete the registration and activate your Gradido account:",
- "subject": "Gradido: Email Verification"
+ "pleaseClickLink": "Please click here to complete the registration and activate your Gradido account.",
+ "subject": "Email Verification",
+ "title": "Email Verification"
},
"accountMultiRegistration": {
+ "contactSupport": "Contact support",
"emailExists": "However, an account already exists for your email address.",
"emailReused": "Your email address has just been used again to register an account with Gradido.",
- "ifYouAreNotTheOne": "If you are not the one who tried to register again, please contact our support:",
- "onForgottenPasswordClickLink": "Please click on the following link if you have forgotten your password:",
- "onForgottenPasswordCopyLink": "or copy the link above into your browser window.",
- "subject": "Gradido: Try To Register Again With Your Email"
+ "ifYouAreNotTheOne": "If you did not try to register again, please contact our support:",
+ "onForgottenPasswordClickLink": "If you have forgotten your password, please click here.",
+ "subject": "Try To Register Again With Your Email",
+ "title": "Try To Register Again With Your Email"
},
"addedContributionMessage": {
- "commonGoodContributionMessage": "you have received a message from {senderFirstName} {senderLastName} regarding your common good contribution “{contributionMemo}”.",
- "subject": "Gradido: Message about your common good contribution",
- "toSeeAndAnswerMessage": "To view and reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab!"
+ "commonGoodContributionMessage": "You have received a message from {senderFirstName} {senderLastName} regarding your common good contribution “{contributionMemo}”.",
+ "readMessage": "Read and reply to message",
+ "subject": "Message about your common good contribution",
+ "title": "Message about your common good contribution",
+ "toSeeAndAnswerMessage": "To view and reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab."
+ },
+ "contribution": {
+ "toSeeContributionsAndMessages": "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."
},
"contributionConfirmed": {
- "commonGoodContributionConfirmed": "Your public good contribution “{contributionMemo}” has just been confirmed by {senderFirstName} {senderLastName} and credited to your Gradido account.",
- "subject": "Gradido: Your contribution to the common good was confirmed"
+ "commonGoodContributionConfirmed": "Your common good contribution “{contributionMemo}” has just been approved by {senderFirstName} {senderLastName}. Your Gradido account has been credited with {amountGDD} GDD.",
+ "subject": "Your contribution to the common good was confirmed",
+ "title": "Your contribution to the common good was confirmed"
},
"contributionDeleted": {
- "commonGoodContributionDeleted": "Your public good contribution “{contributionMemo}” was deleted by {senderFirstName} {senderLastName}.",
- "subject": "Gradido: Your common good contribution was deleted",
- "toSeeContributionsAndMessages": "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!"
+ "commonGoodContributionDeleted": "Your common good contribution “{contributionMemo}” was deleted by {senderFirstName} {senderLastName}.",
+ "subject": "Your common good contribution was deleted",
+ "title": "Your common good contribution was deleted"
},
"contributionDenied": {
- "commonGoodContributionDenied": "Your public good contribution “{contributionMemo}” was rejected by {senderFirstName} {senderLastName}.",
- "subject": "Gradido: Your common good contribution was rejected",
- "toSeeContributionsAndMessages": "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!"
+ "commonGoodContributionDenied": "Your common good contribution “{contributionMemo}” was rejected by {senderFirstName} {senderLastName}.",
+ "subject": "Your common good contribution was rejected",
+ "title": "Your common good contribution was rejected"
+ },
+ "footer": {
+ "contactOurSupport": "If you have any further questions, please contact our support.",
+ "imprint": "Impressum",
+ "imprintAddress": "Gradido-Akademie\nInstitut für Wirtschaftsbionik\nPfarrweg 2\n74653 Künzelsau\nDeutschland",
+ "imprintImageAlt": "Gradido-Akademie Logo",
+ "privacyPolicy": "Privacy Policy",
+ "supportEmail": "support@gradido.net"
},
"general": {
"amountGDD": "Amount: {amountGDD} GDD",
- "detailsYouFindOnLinkToYourAccount": "You can find transaction details in your Gradido account:",
- "doNotAnswer": "do not answer",
- "helloName": "Hello {firstName} {lastName}",
- "linkToYourAccount": "Link to your account:",
- "orCopyLink": "or copy the link above into your browser window.",
- "pleaseDoNotReply": "Please do not reply to this email!",
+ "completeRegistration": "Complete registration",
+ "contribution": "Contribution: : {contributionMemo}",
+ "contributionDetails": "Contribution details",
+ "detailsYouFindOnLinkToYourAccount": "You can find transaction details in your Gradido account.",
+ "helloName": "Hello {firstName} {lastName},",
+ "linkValidity": "The link has a validity of {hours} hours.\nIf the validity of the link has already expired, you can have a new link sent to you here.",
+ "linkValidityWithMinutes": "The link has a validity of {hours} hours and {minutes} minutes.\nIf the validity of the link has already expired, you can have a new link sent to you here.",
+ "newLink": "New link",
+ "orCopyLink": "Or copy the link into your browser window.",
+ "pleaseDoNotReply": "Please do not reply to this email.",
+ "requestNewLink": "Request new valid link",
+ "reset": "reset",
"sincerelyYours": "Kind regards,",
+ "toAccount": "To account",
+ "transactionDetails": "Transaction details",
"yourGradidoTeam": "your Gradido team"
},
"resetPassword": {
- "duration": "The link has a validity of {hours} hours and {minutes} minutes. If the validity of the link has already expired, you can have a new link sent to you here:",
- "pleaseClickLink": "If it was you, please click on the link:",
- "subject": "Gradido: Reset password",
+ "pleaseClickLink": "If it was you, please click here.",
+ "subject": "Reset password",
+ "title": "Reset password",
"youOrSomeoneResetPassword": "You, or someone else, requested a password reset for this account."
},
"transactionLinkRedeemed": {
"hasRedeemedYourLink": "{senderFirstName} {senderLastName} ({senderEmail}) has just redeemed your link.",
"memo": "Message: {transactionMemo}",
- "subject": "Gradido: {senderFirstName} {senderLastName} has redeemed your Gradido link"
+ "subject": "{senderFirstName} {senderLastName} has redeemed your Gradido link",
+ "title": "{senderFirstName} {senderLastName} has redeemed your Gradido link"
},
"transactionReceived": {
"haveReceivedAmountGDDFrom": "You have just received {transactionAmount} GDD from {senderFirstName} {senderLastName} ({senderEmail}).",
- "subject": "Gradido: {senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido"
+ "subject": "{senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido",
+ "title": "{senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido"
}
},
"general": {
- "decimalSeparator": ".",
- "imprint": "Gradido-Akademie\nInstitut für Wirtschaftsbionik\nPfarrweg 2\n74653 Künzelsau\nDeutschland",
- "imprintImageAlt": "Gradido-Akademie Logo",
- "imprintImageURL": "https://gdd.gradido.net/img/brand/green.png"
+ "decimalSeparator": "."
}
}
diff --git a/backend/src/middleware/klicktippMiddleware.ts b/backend/src/middleware/klicktippMiddleware.ts
deleted file mode 100644
index 038bd3dd3..000000000
--- a/backend/src/middleware/klicktippMiddleware.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/* eslint-disable @typescript-eslint/no-unsafe-return */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
-/* eslint-disable @typescript-eslint/restrict-template-expressions */
-/* eslint-disable @typescript-eslint/no-unsafe-argument */
-import { MiddlewareFn } from 'type-graphql'
-
-import { KlickTipp } from '@model/KlickTipp'
-
-import { getKlickTippUser } from '@/apis/KlicktippController'
-import { klickTippLogger as logger } from '@/server/logger'
-
-export const klicktippNewsletterStateMiddleware: MiddlewareFn = async (
- /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
- { root, args, context, info },
- next,
-) => {
- // eslint-disable-next-line n/callback-return
- const result = await next()
- let klickTipp = new KlickTipp({ status: 'Unsubscribed' })
- try {
- const klickTippUser = await getKlickTippUser(result.email)
- if (klickTippUser) {
- klickTipp = new KlickTipp(klickTippUser)
- }
- } catch (err) {
- logger.error(`There is no user for (email='${result.email}') ${err}`)
- }
- result.klickTipp = klickTipp
- return result
-}
diff --git a/backend/src/password/EncryptorUtils.ts b/backend/src/password/EncryptorUtils.ts
index 827fc9547..64dcb2289 100644
--- a/backend/src/password/EncryptorUtils.ts
+++ b/backend/src/password/EncryptorUtils.ts
@@ -10,8 +10,19 @@ import { CONFIG } from '@/config'
import { LogError } from '@/server/LogError'
import { backendLogger as logger } from '@/server/logger'
-// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-commonjs
-const sodium = require('sodium-native')
+import {
+ crypto_shorthash_KEYBYTES,
+ crypto_box_SEEDBYTES,
+ crypto_hash_sha512_init,
+ crypto_hash_sha512_update,
+ crypto_hash_sha512_final,
+ crypto_hash_sha512_BYTES,
+ crypto_hash_sha512_STATEBYTES,
+ crypto_shorthash_BYTES,
+ crypto_pwhash_SALTBYTES,
+ crypto_pwhash,
+ crypto_shorthash,
+} from 'sodium-native'
// We will reuse this for changePassword
export const isValidPassword = (password: string): boolean => {
@@ -22,36 +33,36 @@ export const SecretKeyCryptographyCreateKey = (salt: string, password: string):
logger.trace('SecretKeyCryptographyCreateKey...')
const configLoginAppSecret = Buffer.from(CONFIG.LOGIN_APP_SECRET, 'hex')
const configLoginServerKey = Buffer.from(CONFIG.LOGIN_SERVER_KEY, 'hex')
- if (configLoginServerKey.length !== sodium.crypto_shorthash_KEYBYTES) {
+ if (configLoginServerKey.length !== crypto_shorthash_KEYBYTES) {
throw new LogError(
'ServerKey has an invalid size',
configLoginServerKey.length,
- sodium.crypto_shorthash_KEYBYTES,
+ crypto_shorthash_KEYBYTES,
)
}
- const state = Buffer.alloc(sodium.crypto_hash_sha512_STATEBYTES)
- sodium.crypto_hash_sha512_init(state)
- sodium.crypto_hash_sha512_update(state, Buffer.from(salt))
- sodium.crypto_hash_sha512_update(state, configLoginAppSecret)
- const hash = Buffer.alloc(sodium.crypto_hash_sha512_BYTES)
- sodium.crypto_hash_sha512_final(state, hash)
+ const state = Buffer.alloc(crypto_hash_sha512_STATEBYTES)
+ crypto_hash_sha512_init(state)
+ crypto_hash_sha512_update(state, Buffer.from(salt))
+ crypto_hash_sha512_update(state, configLoginAppSecret)
+ const hash = Buffer.alloc(crypto_hash_sha512_BYTES)
+ crypto_hash_sha512_final(state, hash)
- const encryptionKey = Buffer.alloc(sodium.crypto_box_SEEDBYTES)
+ const encryptionKey = Buffer.alloc(crypto_box_SEEDBYTES)
const opsLimit = 10
const memLimit = 33554432
const algo = 2
- sodium.crypto_pwhash(
+ crypto_pwhash(
encryptionKey,
Buffer.from(password),
- hash.slice(0, sodium.crypto_pwhash_SALTBYTES),
+ hash.slice(0, crypto_pwhash_SALTBYTES),
opsLimit,
memLimit,
algo,
)
- const encryptionKeyHash = Buffer.alloc(sodium.crypto_shorthash_BYTES)
- sodium.crypto_shorthash(encryptionKeyHash, encryptionKey, configLoginServerKey)
+ const encryptionKeyHash = Buffer.alloc(crypto_shorthash_BYTES)
+ crypto_shorthash(encryptionKeyHash, encryptionKey, configLoginServerKey)
return [encryptionKeyHash, encryptionKey]
}
diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts
index ce7efbfc3..a964cdb3a 100644
--- a/backend/src/seeds/graphql/queries.ts
+++ b/backend/src/seeds/graphql/queries.ts
@@ -69,12 +69,19 @@ export const sendResetPasswordEmail = gql`
`
export const searchUsers = gql`
- query ($searchText: String!, $currentPage: Int, $pageSize: Int, $filters: SearchUsersFilters) {
+ query (
+ $query: String!
+ $filters: SearchUsersFilters
+ $currentPage: Int = 1
+ $pageSize: Int = 25
+ $order: Order = ASC
+ ) {
searchUsers(
- searchText: $searchText
+ query: $query
+ filters: $filters
currentPage: $currentPage
pageSize: $pageSize
- filters: $filters
+ order: $order
) {
userCount
userList {
diff --git a/backend/src/typeorm/repository/User.ts b/backend/src/typeorm/repository/User.ts
index 53273102d..f54859f41 100644
--- a/backend/src/typeorm/repository/User.ts
+++ b/backend/src/typeorm/repository/User.ts
@@ -1,7 +1,8 @@
import { Brackets, EntityRepository, IsNull, Not, Repository } from '@dbTools/typeorm'
import { User as DbUser } from '@entity/User'
-import { SearchUsersFilters } from '@/graphql/arg/SearchUsersFilters'
+import { SearchUsersFilters } from '@arg/SearchUsersFilters'
+import { Order } from '@enum/Order'
@EntityRepository(DbUser)
export class UserRepository extends Repository {
@@ -11,6 +12,7 @@ export class UserRepository extends Repository {
filters: SearchUsersFilters | null,
currentPage: number,
pageSize: number,
+ order = Order.ASC,
): Promise<[DbUser[], number]> {
const query = this.createQueryBuilder('user')
.select(select)
@@ -46,6 +48,7 @@ export class UserRepository extends Repository {
}
return query
+ .orderBy({ 'user.id': order })
.take(pageSize)
.skip((currentPage - 1) * pageSize)
.getManyAndCount()
diff --git a/backend/yarn.lock b/backend/yarn.lock
index 3c7958488..1cfb4d8ff 100644
--- a/backend/yarn.lock
+++ b/backend/yarn.lock
@@ -1189,6 +1189,13 @@
"@types/mime" "^1"
"@types/node" "*"
+"@types/sodium-native@^2.3.5":
+ version "2.3.5"
+ resolved "https://registry.yarnpkg.com/@types/sodium-native/-/sodium-native-2.3.5.tgz#5d2681e7b6b67bcbdc63cfb133e303ec9e942e43"
+ integrity sha512-a3DAIpW8+36XAY8aIR36JBQQsfOabxHuJwx11DL/PTvnbwEWPAXW66b8QbMi0r2vUnkOfREsketxdvjBmQxqDQ==
+ dependencies:
+ "@types/node" "*"
+
"@types/stack-utils@^2.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
diff --git a/database/.eslintrc.js b/database/.eslintrc.js
index 587506ecc..6f1db58ff 100644
--- a/database/.eslintrc.js
+++ b/database/.eslintrc.js
@@ -10,10 +10,10 @@ module.exports = {
'standard',
'eslint:recommended',
'plugin:prettier/recommended',
- // 'plugin:import/recommended',
- // 'plugin:import/typescript',
+ 'plugin:import/recommended',
+ 'plugin:import/typescript',
// 'plugin:security/recommended',
- // 'plugin:@eslint-community/eslint-comments/recommended',
+ 'plugin:@eslint-community/eslint-comments/recommended',
],
settings: {
'import/parsers': {
@@ -37,107 +37,107 @@ module.exports = {
},
],
// import
- // 'import/export': 'error',
- // 'import/no-deprecated': 'error',
- // 'import/no-empty-named-blocks': 'error',
+ 'import/export': 'error',
+ 'import/no-deprecated': 'error',
+ 'import/no-empty-named-blocks': 'error',
// 'import/no-extraneous-dependencies': 'error',
- // 'import/no-mutable-exports': 'error',
- // 'import/no-unused-modules': 'error',
- // 'import/no-named-as-default': 'error',
- // 'import/no-named-as-default-member': 'error',
- // 'import/no-amd': 'error',
- // 'import/no-commonjs': 'error',
- // 'import/no-import-module-exports': 'error',
- // 'import/no-nodejs-modules': 'off',
- // 'import/unambiguous': 'error',
- // 'import/default': 'error',
- // 'import/named': 'error',
- // 'import/namespace': 'error',
- // 'import/no-absolute-path': 'error',
+ 'import/no-mutable-exports': 'error',
+ 'import/no-unused-modules': 'error',
+ 'import/no-named-as-default': 'error',
+ 'import/no-named-as-default-member': 'error',
+ 'import/no-amd': 'error',
+ 'import/no-commonjs': 'error',
+ 'import/no-import-module-exports': 'error',
+ 'import/no-nodejs-modules': 'off',
+ 'import/unambiguous': 'error',
+ 'import/default': 'error',
+ 'import/named': 'error',
+ 'import/namespace': 'error',
+ 'import/no-absolute-path': 'error',
// 'import/no-cycle': 'error',
- // 'import/no-dynamic-require': 'error',
- // 'import/no-internal-modules': 'off',
- // 'import/no-relative-packages': 'error',
+ 'import/no-dynamic-require': 'error',
+ 'import/no-internal-modules': 'off',
+ 'import/no-relative-packages': 'error',
// 'import/no-relative-parent-imports': ['error', { ignore: ['@/*'] }],
- // 'import/no-self-import': 'error',
- // 'import/no-unresolved': 'error',
- // 'import/no-useless-path-segments': 'error',
- // 'import/no-webpack-loader-syntax': 'error',
- // 'import/consistent-type-specifier-style': 'error',
- // 'import/exports-last': 'off',
- // 'import/extensions': 'error',
- // 'import/first': 'error',
- // 'import/group-exports': 'off',
- // 'import/newline-after-import': 'error',
- // 'import/no-anonymous-default-export': 'error',
- // 'import/no-default-export': 'error',
- // 'import/no-duplicates': 'error',
- // 'import/no-named-default': 'error',
- // 'import/no-namespace': 'error',
- // 'import/no-unassigned-import': 'error',
+ 'import/no-self-import': 'error',
+ 'import/no-unresolved': 'error',
+ 'import/no-useless-path-segments': 'error',
+ 'import/no-webpack-loader-syntax': 'error',
+ 'import/consistent-type-specifier-style': 'error',
+ 'import/exports-last': 'off',
+ 'import/extensions': 'error',
+ 'import/first': 'error',
+ 'import/group-exports': 'off',
+ 'import/newline-after-import': 'error',
+ 'import/no-anonymous-default-export': 'error',
+ 'import/no-default-export': 'error',
+ 'import/no-duplicates': 'error',
+ 'import/no-named-default': 'error',
+ 'import/no-namespace': 'error',
+ 'import/no-unassigned-import': 'error',
// 'import/order': [
- // 'error',
- // {
- // groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
- // 'newlines-between': 'always',
- // pathGroups: [
- // {
- // pattern: '@?*/**',
- // group: 'external',
- // position: 'after',
- // },
- // {
- // pattern: '@/**',
- // group: 'external',
- // position: 'after',
- // },
- // ],
- // alphabetize: {
- // order: 'asc' /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */,
- // caseInsensitive: true /* ignore case. Options: [true, false] */,
+ // 'error',
+ // {
+ // groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
+ // 'newlines-between': 'always',
+ // pathGroups: [
+ // {
+ // pattern: '@?*/**',
+ // group: 'external',
+ // position: 'after',
+ // },
+ // {
+ // pattern: '@/**',
+ // group: 'external',
+ // position: 'after',
+ // },
+ // ],
+ // alphabetize: {
+ // order: 'asc' /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */,
+ // caseInsensitive: true /* ignore case. Options: [true, false] */,
// },
// distinctGroup: true,
// },
// ],
- // 'import/prefer-default-export': 'off',
+ 'import/prefer-default-export': 'off',
// n
- // 'n/handle-callback-err': 'error',
- // 'n/no-callback-literal': 'error',
- // 'n/no-exports-assign': 'error',
+ 'n/handle-callback-err': 'error',
+ 'n/no-callback-literal': 'error',
+ 'n/no-exports-assign': 'error',
// 'n/no-extraneous-import': 'error',
- // 'n/no-extraneous-require': 'error',
- // 'n/no-hide-core-modules': 'error',
- // 'n/no-missing-import': 'off', // not compatible with typescript
- // 'n/no-missing-require': 'error',
- // 'n/no-new-require': 'error',
- // 'n/no-path-concat': 'error',
+ 'n/no-extraneous-require': 'error',
+ 'n/no-hide-core-modules': 'error',
+ 'n/no-missing-import': 'off', // not compatible with typescript
+ 'n/no-missing-require': 'error',
+ 'n/no-new-require': 'error',
+ 'n/no-path-concat': 'error',
// 'n/no-process-exit': 'error',
- // 'n/no-unpublished-bin': 'error',
- // 'n/no-unpublished-import': 'off', // TODO need to exclude seeds
- // 'n/no-unpublished-require': 'error',
- // 'n/no-unsupported-features': ['error', { ignores: ['modules'] }],
- // 'n/no-unsupported-features/es-builtins': 'error',
- // 'n/no-unsupported-features/es-syntax': 'error',
- // 'n/no-unsupported-features/node-builtins': 'error',
- // 'n/process-exit-as-throw': 'error',
- // 'n/shebang': 'error',
- // 'n/callback-return': 'error',
- // 'n/exports-style': 'error',
- // 'n/file-extension-in-import': 'off',
- // 'n/global-require': 'error',
- // 'n/no-mixed-requires': 'error',
- // 'n/no-process-env': 'error',
- // 'n/no-restricted-import': 'error',
- // 'n/no-restricted-require': 'error',
+ 'n/no-unpublished-bin': 'error',
+ 'n/no-unpublished-import': 'off', // TODO need to exclude seeds
+ 'n/no-unpublished-require': 'error',
+ 'n/no-unsupported-features': ['error', { ignores: ['modules'] }],
+ 'n/no-unsupported-features/es-builtins': 'error',
+ 'n/no-unsupported-features/es-syntax': 'error',
+ 'n/no-unsupported-features/node-builtins': 'error',
+ 'n/process-exit-as-throw': 'error',
+ 'n/shebang': 'error',
+ 'n/callback-return': 'error',
+ 'n/exports-style': 'error',
+ 'n/file-extension-in-import': 'off',
+ 'n/global-require': 'error',
+ 'n/no-mixed-requires': 'error',
+ 'n/no-process-env': 'error',
+ 'n/no-restricted-import': 'error',
+ 'n/no-restricted-require': 'error',
// 'n/no-sync': 'error',
- // 'n/prefer-global/buffer': 'error',
- // 'n/prefer-global/console': 'error',
- // 'n/prefer-global/process': 'error',
- // 'n/prefer-global/text-decoder': 'error',
- // 'n/prefer-global/text-encoder': 'error',
- // 'n/prefer-global/url': 'error',
- // 'n/prefer-global/url-search-params': 'error',
- // 'n/prefer-promises/dns': 'error',
+ 'n/prefer-global/buffer': 'error',
+ 'n/prefer-global/console': 'error',
+ 'n/prefer-global/process': 'error',
+ 'n/prefer-global/text-decoder': 'error',
+ 'n/prefer-global/text-encoder': 'error',
+ 'n/prefer-global/url': 'error',
+ 'n/prefer-global/url-search-params': 'error',
+ 'n/prefer-promises/dns': 'error',
// 'n/prefer-promises/fs': 'error',
// promise
// 'promise/catch-or-return': 'error',
@@ -155,10 +155,10 @@ module.exports = {
// 'promise/prefer-await-to-callbacks': 'error',
// 'promise/no-multiple-resolved': 'error',
// eslint comments
- // '@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],
- // '@eslint-community/eslint-comments/no-restricted-disable': 'error',
- // '@eslint-community/eslint-comments/no-use': 'off',
- // '@eslint-community/eslint-comments/require-description': 'off',
+ '@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],
+ '@eslint-community/eslint-comments/no-restricted-disable': 'error',
+ '@eslint-community/eslint-comments/no-use': 'off',
+ '@eslint-community/eslint-comments/require-description': 'off',
},
overrides: [
// only for ts files
diff --git a/database/entity/0002-add_settings/User.ts b/database/entity/0002-add_settings/User.ts
index 4f333fd50..c26602cd5 100644
--- a/database/entity/0002-add_settings/User.ts
+++ b/database/entity/0002-add_settings/User.ts
@@ -1,5 +1,5 @@
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm'
-import { UserSetting } from '../0002-add_settings/UserSetting'
+import { UserSetting } from './UserSetting'
// Moriz: I do not like the idea of having two user tables
@Entity('state_users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' })
diff --git a/database/entity/0028-decimal_types/Transaction.ts b/database/entity/0028-decimal_types/Transaction.ts
index 9352e6335..6c08fe3c0 100644
--- a/database/entity/0028-decimal_types/Transaction.ts
+++ b/database/entity/0028-decimal_types/Transaction.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
diff --git a/database/entity/0029-clean_transaction_table/Transaction.ts b/database/entity/0029-clean_transaction_table/Transaction.ts
index 5931c153f..f253b9d58 100644
--- a/database/entity/0029-clean_transaction_table/Transaction.ts
+++ b/database/entity/0029-clean_transaction_table/Transaction.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
diff --git a/database/entity/0030-transaction_link/TransactionLink.ts b/database/entity/0030-transaction_link/TransactionLink.ts
index 177f23561..59179c3be 100644
--- a/database/entity/0030-transaction_link/TransactionLink.ts
+++ b/database/entity/0030-transaction_link/TransactionLink.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, DeleteDateColumn } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
diff --git a/database/entity/0031-remove_sendEmail_from_transaction_link/TransactionLink.ts b/database/entity/0031-remove_sendEmail_from_transaction_link/TransactionLink.ts
index 9cd42258a..6c8edf30f 100644
--- a/database/entity/0031-remove_sendEmail_from_transaction_link/TransactionLink.ts
+++ b/database/entity/0031-remove_sendEmail_from_transaction_link/TransactionLink.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, DeleteDateColumn } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
diff --git a/database/entity/0032-add-transaction-link-to-transaction/Transaction.ts b/database/entity/0032-add-transaction-link-to-transaction/Transaction.ts
index 398fa03db..e9e206e14 100644
--- a/database/entity/0032-add-transaction-link-to-transaction/Transaction.ts
+++ b/database/entity/0032-add-transaction-link-to-transaction/Transaction.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
diff --git a/database/entity/0035-admin_pending_creations_decimal/AdminPendingCreation.ts b/database/entity/0035-admin_pending_creations_decimal/AdminPendingCreation.ts
index 3cd83a3a5..f2d0d1386 100644
--- a/database/entity/0035-admin_pending_creations_decimal/AdminPendingCreation.ts
+++ b/database/entity/0035-admin_pending_creations_decimal/AdminPendingCreation.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
diff --git a/database/entity/0036-unique_previous_in_transactions/Transaction.ts b/database/entity/0036-unique_previous_in_transactions/Transaction.ts
index 3b6baf47a..2f2899429 100644
--- a/database/entity/0036-unique_previous_in_transactions/Transaction.ts
+++ b/database/entity/0036-unique_previous_in_transactions/Transaction.ts
@@ -1,5 +1,5 @@
/* eslint-disable no-use-before-define */
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
import { Contribution } from '../Contribution'
diff --git a/database/entity/0038-add_contribution_links_table/ContributionLink.ts b/database/entity/0038-add_contribution_links_table/ContributionLink.ts
index 496f57d71..3d79e84fd 100644
--- a/database/entity/0038-add_contribution_links_table/ContributionLink.ts
+++ b/database/entity/0038-add_contribution_links_table/ContributionLink.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, DeleteDateColumn } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
diff --git a/database/entity/0039-contributions_table/Contribution.ts b/database/entity/0039-contributions_table/Contribution.ts
index b5e6ac0e0..7b0abd29a 100644
--- a/database/entity/0039-contributions_table/Contribution.ts
+++ b/database/entity/0039-contributions_table/Contribution.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import {
BaseEntity,
Column,
diff --git a/database/entity/0043-add_event_protocol_table/EventProtocol.ts b/database/entity/0043-add_event_protocol_table/EventProtocol.ts
index 72470d2ed..13eebcce5 100644
--- a/database/entity/0043-add_event_protocol_table/EventProtocol.ts
+++ b/database/entity/0043-add_event_protocol_table/EventProtocol.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
diff --git a/database/entity/0045-add_denied_type_and_status_to_contributions/Contribution.ts b/database/entity/0045-add_denied_type_and_status_to_contributions/Contribution.ts
index c376ae53e..21300fd4d 100644
--- a/database/entity/0045-add_denied_type_and_status_to_contributions/Contribution.ts
+++ b/database/entity/0045-add_denied_type_and_status_to_contributions/Contribution.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import {
BaseEntity,
Column,
diff --git a/database/entity/0047-messages_tables/Contribution.ts b/database/entity/0047-messages_tables/Contribution.ts
index 1ba31bb88..323bf91b6 100644
--- a/database/entity/0047-messages_tables/Contribution.ts
+++ b/database/entity/0047-messages_tables/Contribution.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import {
BaseEntity,
Column,
diff --git a/database/entity/0050-add_messageId_to_event_protocol/EventProtocol.ts b/database/entity/0050-add_messageId_to_event_protocol/EventProtocol.ts
index e457cc0a3..ca7d27069 100644
--- a/database/entity/0050-add_messageId_to_event_protocol/EventProtocol.ts
+++ b/database/entity/0050-add_messageId_to_event_protocol/EventProtocol.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
diff --git a/database/entity/0051-add_delete_by_to_contributions/Contribution.ts b/database/entity/0051-add_delete_by_to_contributions/Contribution.ts
index 32c6f32a3..8e8d0d172 100644
--- a/database/entity/0051-add_delete_by_to_contributions/Contribution.ts
+++ b/database/entity/0051-add_delete_by_to_contributions/Contribution.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import {
BaseEntity,
Column,
diff --git a/database/entity/0052-add_updated_at_to_contributions/Contribution.ts b/database/entity/0052-add_updated_at_to_contributions/Contribution.ts
index 4676c14af..941e9da38 100644
--- a/database/entity/0052-add_updated_at_to_contributions/Contribution.ts
+++ b/database/entity/0052-add_updated_at_to_contributions/Contribution.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import {
BaseEntity,
Column,
diff --git a/database/entity/0061-event_refactoring/Event.ts b/database/entity/0061-event_refactoring/Event.ts
index ab75c2d94..a2fbf0adf 100644
--- a/database/entity/0061-event_refactoring/Event.ts
+++ b/database/entity/0061-event_refactoring/Event.ts
@@ -2,7 +2,7 @@ import { Contribution } from '../Contribution'
import { ContributionMessage } from '../ContributionMessage'
import { User } from '../User'
import { Transaction } from '../Transaction'
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import {
BaseEntity,
Entity,
diff --git a/database/entity/0063-event_link_fields/Event.ts b/database/entity/0063-event_link_fields/Event.ts
index dc7fa776c..40f1ea7c0 100644
--- a/database/entity/0063-event_link_fields/Event.ts
+++ b/database/entity/0063-event_link_fields/Event.ts
@@ -2,7 +2,7 @@ import { Contribution } from '../Contribution'
import { ContributionMessage } from '../ContributionMessage'
import { User } from '../User'
import { Transaction } from '../Transaction'
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import {
BaseEntity,
Entity,
diff --git a/database/entity/0066-x-community-sendcoins-transactions_table/Transaction.ts b/database/entity/0066-x-community-sendcoins-transactions_table/Transaction.ts
index 319bd81de..105972310 100644
--- a/database/entity/0066-x-community-sendcoins-transactions_table/Transaction.ts
+++ b/database/entity/0066-x-community-sendcoins-transactions_table/Transaction.ts
@@ -1,5 +1,5 @@
/* eslint-disable no-use-before-define */
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
import { Contribution } from '../Contribution'
diff --git a/database/entity/0067-private_key_in_community_table/Community.ts b/database/entity/0067-private_key_in_community_table/Community.ts
new file mode 100644
index 000000000..dcb55c875
--- /dev/null
+++ b/database/entity/0067-private_key_in_community_table/Community.ts
@@ -0,0 +1,63 @@
+import {
+ BaseEntity,
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ CreateDateColumn,
+ UpdateDateColumn,
+} from 'typeorm'
+
+@Entity('communities')
+export class Community extends BaseEntity {
+ @PrimaryGeneratedColumn('increment', { unsigned: true })
+ id: number
+
+ @Column({ name: 'foreign', type: 'bool', nullable: false, default: true })
+ foreign: boolean
+
+ @Column({ name: 'url', length: 255, nullable: false })
+ url: string
+
+ @Column({ name: 'public_key', type: 'binary', length: 64, nullable: false })
+ publicKey: Buffer
+
+ @Column({ name: 'private_key', type: 'binary', length: 64, nullable: true })
+ privateKey: Buffer | null
+
+ @Column({
+ name: 'community_uuid',
+ type: 'char',
+ length: 36,
+ nullable: true,
+ collation: 'utf8mb4_unicode_ci',
+ })
+ communityUuid: string | null
+
+ @Column({ name: 'authenticated_at', type: 'datetime', nullable: true })
+ authenticatedAt: Date | null
+
+ @Column({ name: 'name', type: 'varchar', length: 40, nullable: true })
+ name: string | null
+
+ @Column({ name: 'description', type: 'varchar', length: 255, nullable: true })
+ description: string | null
+
+ @CreateDateColumn({ name: 'creation_date', type: 'datetime', nullable: true })
+ creationDate: Date | null
+
+ @CreateDateColumn({
+ name: 'created_at',
+ type: 'datetime',
+ default: () => 'CURRENT_TIMESTAMP(3)',
+ nullable: false,
+ })
+ createdAt: Date
+
+ @UpdateDateColumn({
+ name: 'updated_at',
+ type: 'datetime',
+ onUpdate: 'CURRENT_TIMESTAMP(3)',
+ nullable: true,
+ })
+ updatedAt: Date | null
+}
diff --git a/database/entity/Community.ts b/database/entity/Community.ts
index ee08323b6..5df0f70fe 100644
--- a/database/entity/Community.ts
+++ b/database/entity/Community.ts
@@ -1 +1 @@
-export { Community } from './0065-refactor_communities_table/Community'
+export { Community } from './0067-private_key_in_community_table/Community'
diff --git a/database/migrations/0028-decimal_types.ts b/database/migrations/0028-decimal_types.ts
index e79d120a8..742a370ba 100644
--- a/database/migrations/0028-decimal_types.ts
+++ b/database/migrations/0028-decimal_types.ts
@@ -20,9 +20,8 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable @typescript-eslint/no-explicit-any */
-/* eslint-disable no-unused-vars */
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
// Set precision value
Decimal.set({
@@ -41,11 +40,13 @@ interface Decay {
duration: number | null
}
+/* eslint-disable no-unused-vars */
export enum TransactionTypeId {
CREATION = 1,
SEND = 2,
RECEIVE = 3,
}
+/* eslint-enable no-unused-vars */
function decayFormula(value: Decimal, seconds: number): Decimal {
return value.mul(new Decimal('0.99999997803504048973201202316767079413460520837376').pow(seconds))
diff --git a/database/migrations/0054-recalculate_balance_and_decay.ts b/database/migrations/0054-recalculate_balance_and_decay.ts
index b2add3a58..7c567c36a 100644
--- a/database/migrations/0054-recalculate_balance_and_decay.ts
+++ b/database/migrations/0054-recalculate_balance_and_decay.ts
@@ -15,7 +15,7 @@
/* eslint-disable no-unused-vars */
import fs from 'fs'
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
// Set precision value
Decimal.set({
@@ -156,6 +156,5 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
}
}
-/* eslint-disable @typescript-eslint/no-empty-function */
-/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
+/* eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function */
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) {}
diff --git a/database/migrations/0055-consistent_deleted_users.ts b/database/migrations/0055-consistent_deleted_users.ts
index 561e0541a..93d5cb575 100644
--- a/database/migrations/0055-consistent_deleted_users.ts
+++ b/database/migrations/0055-consistent_deleted_users.ts
@@ -11,6 +11,5 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
AND users.deleted_at IS NOT NULL;`)
}
-/* eslint-disable @typescript-eslint/no-empty-function */
-/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
+/* eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function */
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) {}
diff --git a/database/migrations/0056-consistent_transactions_table.ts b/database/migrations/0056-consistent_transactions_table.ts
index 02ed3b7be..0d8721f07 100644
--- a/database/migrations/0056-consistent_transactions_table.ts
+++ b/database/migrations/0056-consistent_transactions_table.ts
@@ -34,6 +34,5 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
}
}
-/* eslint-disable @typescript-eslint/no-empty-function */
-/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
+/* eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function */
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) {}
diff --git a/database/migrations/0067-private_key_in_community_table.ts b/database/migrations/0067-private_key_in_community_table.ts
new file mode 100644
index 000000000..f36e68b16
--- /dev/null
+++ b/database/migrations/0067-private_key_in_community_table.ts
@@ -0,0 +1,17 @@
+/* MIGRATION TO ADD PRIVATE KEY IN COMMUNITY TABLE
+ *
+ * This migration adds a field for the private key in the community.table
+ */
+
+/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
+export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) {
+ await queryFn(
+ 'ALTER TABLE `communities` ADD COLUMN `private_key` binary(64) DEFAULT NULL AFTER `public_key`;',
+ )
+}
+
+export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) {
+ await queryFn('ALTER TABLE `communities` DROP COLUMN `private_key`;')
+}
diff --git a/database/package.json b/database/package.json
index 65b76ca14..abc69d21d 100644
--- a/database/package.json
+++ b/database/package.json
@@ -48,5 +48,8 @@
"ts-mysql-migrate": "^1.0.2",
"typeorm": "^0.2.38",
"uuid": "^8.3.2"
+ },
+ "engines": {
+ "node": ">=14"
}
}
diff --git a/database/src/config/index.ts b/database/src/config/index.ts
index ba41f11d4..0fc8cf9c5 100644
--- a/database/src/config/index.ts
+++ b/database/src/config/index.ts
@@ -1,6 +1,7 @@
-// ATTENTION: DO NOT PUT ANY SECRETS IN HERE (or the .env)
+/* eslint-disable n/no-process-env */
import dotenv from 'dotenv'
+
dotenv.config()
const constants = {
@@ -35,6 +36,4 @@ if (
)
}
-const CONFIG = { ...constants, ...database, ...migrations }
-
-export default CONFIG
+export const CONFIG = { ...constants, ...database, ...migrations }
diff --git a/database/src/index.ts b/database/src/index.ts
index 48056ab55..96785a721 100644
--- a/database/src/index.ts
+++ b/database/src/index.ts
@@ -1,6 +1,5 @@
-import 'reflect-metadata'
import { createDatabase } from './prepare'
-import CONFIG from './config'
+import { CONFIG } from './config'
import { createPool } from 'mysql'
import { Migration } from 'ts-mysql-migrate'
diff --git a/database/src/prepare.ts b/database/src/prepare.ts
index 3c64b1c5e..2ecbb4c42 100644
--- a/database/src/prepare.ts
+++ b/database/src/prepare.ts
@@ -1,6 +1,6 @@
import { createConnection } from 'mysql2/promise'
-import CONFIG from './config'
+import { CONFIG } from './config'
export const createDatabase = async (): Promise => {
const con = await createConnection({
diff --git a/database/src/typeorm/DecimalTransformer.ts b/database/src/typeorm/DecimalTransformer.ts
index 92efaf3bc..b1bcb8ca3 100644
--- a/database/src/typeorm/DecimalTransformer.ts
+++ b/database/src/typeorm/DecimalTransformer.ts
@@ -1,4 +1,4 @@
-import Decimal from 'decimal.js-light'
+import { Decimal } from 'decimal.js-light'
import { ValueTransformer } from 'typeorm'
Decimal.set({
diff --git a/dht-node/.eslintignore b/dht-node/.eslintignore
index f6b255e92..1ae86fe5e 100644
--- a/dht-node/.eslintignore
+++ b/dht-node/.eslintignore
@@ -1,3 +1,4 @@
node_modules
**/*.min.js
-build
\ No newline at end of file
+build
+coverage
\ No newline at end of file
diff --git a/dht-node/.eslintrc.js b/dht-node/.eslintrc.js
index 64f5a9051..c477a4cb1 100644
--- a/dht-node/.eslintrc.js
+++ b/dht-node/.eslintrc.js
@@ -13,7 +13,7 @@ module.exports = {
// 'plugin:import/recommended',
// 'plugin:import/typescript',
// 'plugin:security/recommended',
- // 'plugin:@eslint-community/eslint-comments/recommended',
+ 'plugin:@eslint-community/eslint-comments/recommended',
],
settings: {
'import/parsers': {
@@ -101,44 +101,44 @@ module.exports = {
// ],
// 'import/prefer-default-export': 'off',
// n
- // 'n/handle-callback-err': 'error',
- // 'n/no-callback-literal': 'error',
- // 'n/no-exports-assign': 'error',
- // 'n/no-extraneous-import': 'error',
- // 'n/no-extraneous-require': 'error',
- // 'n/no-hide-core-modules': 'error',
- // 'n/no-missing-import': 'off', // not compatible with typescript
- // 'n/no-missing-require': 'error',
- // 'n/no-new-require': 'error',
- // 'n/no-path-concat': 'error',
- // 'n/no-process-exit': 'error',
- // 'n/no-unpublished-bin': 'error',
- // 'n/no-unpublished-import': 'off', // TODO need to exclude seeds
- // 'n/no-unpublished-require': 'error',
- // 'n/no-unsupported-features': ['error', { ignores: ['modules'] }],
- // 'n/no-unsupported-features/es-builtins': 'error',
- // 'n/no-unsupported-features/es-syntax': 'error',
- // 'n/no-unsupported-features/node-builtins': 'error',
- // 'n/process-exit-as-throw': 'error',
- // 'n/shebang': 'error',
- // 'n/callback-return': 'error',
- // 'n/exports-style': 'error',
- // 'n/file-extension-in-import': 'off',
- // 'n/global-require': 'error',
- // 'n/no-mixed-requires': 'error',
- // 'n/no-process-env': 'error',
- // 'n/no-restricted-import': 'error',
- // 'n/no-restricted-require': 'error',
- // 'n/no-sync': 'error',
- // 'n/prefer-global/buffer': 'error',
- // 'n/prefer-global/console': 'error',
- // 'n/prefer-global/process': 'error',
- // 'n/prefer-global/text-decoder': 'error',
- // 'n/prefer-global/text-encoder': 'error',
- // 'n/prefer-global/url': 'error',
- // 'n/prefer-global/url-search-params': 'error',
- // 'n/prefer-promises/dns': 'error',
- // 'n/prefer-promises/fs': 'error',
+ 'n/handle-callback-err': 'error',
+ 'n/no-callback-literal': 'error',
+ 'n/no-exports-assign': 'error',
+ 'n/no-extraneous-import': 'error',
+ 'n/no-extraneous-require': 'error',
+ 'n/no-hide-core-modules': 'error',
+ 'n/no-missing-import': 'off', // not compatible with typescript
+ 'n/no-missing-require': 'error',
+ 'n/no-new-require': 'error',
+ 'n/no-path-concat': 'error',
+ 'n/no-process-exit': 'error',
+ 'n/no-unpublished-bin': 'error',
+ 'n/no-unpublished-import': 'off', // TODO need to exclude seeds
+ 'n/no-unpublished-require': 'error',
+ 'n/no-unsupported-features': ['error', { ignores: ['modules'] }],
+ 'n/no-unsupported-features/es-builtins': 'error',
+ 'n/no-unsupported-features/es-syntax': 'error',
+ 'n/no-unsupported-features/node-builtins': 'error',
+ 'n/process-exit-as-throw': 'error',
+ 'n/shebang': 'error',
+ 'n/callback-return': 'error',
+ 'n/exports-style': 'error',
+ 'n/file-extension-in-import': 'off',
+ 'n/global-require': 'error',
+ 'n/no-mixed-requires': 'error',
+ 'n/no-process-env': 'error',
+ 'n/no-restricted-import': 'error',
+ 'n/no-restricted-require': 'error',
+ 'n/no-sync': 'error',
+ 'n/prefer-global/buffer': 'error',
+ 'n/prefer-global/console': 'error',
+ 'n/prefer-global/process': 'error',
+ 'n/prefer-global/text-decoder': 'error',
+ 'n/prefer-global/text-encoder': 'error',
+ 'n/prefer-global/url': 'error',
+ 'n/prefer-global/url-search-params': 'error',
+ 'n/prefer-promises/dns': 'error',
+ 'n/prefer-promises/fs': 'error',
// promise
// 'promise/catch-or-return': 'error',
// 'promise/no-return-wrap': 'error',
@@ -155,10 +155,10 @@ module.exports = {
// 'promise/prefer-await-to-callbacks': 'error',
// 'promise/no-multiple-resolved': 'error',
// eslint comments
- // '@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],
- // '@eslint-community/eslint-comments/no-restricted-disable': 'error',
- // '@eslint-community/eslint-comments/no-use': 'off',
- // '@eslint-community/eslint-comments/require-description': 'off',
+ '@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],
+ '@eslint-community/eslint-comments/no-restricted-disable': 'error',
+ '@eslint-community/eslint-comments/no-use': 'off',
+ '@eslint-community/eslint-comments/require-description': 'off',
},
overrides: [
// only for ts files
diff --git a/dht-node/jest.config.js b/dht-node/jest.config.js
index 0b83d8edd..49f048d78 100644
--- a/dht-node/jest.config.js
+++ b/dht-node/jest.config.js
@@ -16,10 +16,12 @@ module.exports = {
'@/(.*)': '/src/$1',
'@test/(.*)': '/test/$1',
'@entity/(.*)':
+ // eslint-disable-next-line n/no-process-env
process.env.NODE_ENV === 'development'
? '/../database/entity/$1'
: '/../database/build/entity/$1',
'@dbTools/(.*)':
+ // eslint-disable-next-line n/no-process-env
process.env.NODE_ENV === 'development'
? '/../database/src/$1'
: '/../database/build/src/$1',
diff --git a/dht-node/package.json b/dht-node/package.json
index 23238b9e4..049d0373f 100644
--- a/dht-node/package.json
+++ b/dht-node/package.json
@@ -47,5 +47,8 @@
"prettier": "^2.8.7",
"jest": "^27.2.4",
"ts-jest": "^27.0.5"
+ },
+ "engines": {
+ "node": ">=14"
}
}
diff --git a/dht-node/src/config/index.ts b/dht-node/src/config/index.ts
index 43949201b..2e43da1cc 100644
--- a/dht-node/src/config/index.ts
+++ b/dht-node/src/config/index.ts
@@ -1,9 +1,9 @@
-// ATTENTION: DO NOT PUT ANY SECRETS IN HERE (or the .env)
+/* eslint-disable n/no-process-env */
import dotenv from 'dotenv'
dotenv.config()
const constants = {
- DB_VERSION: '0066-x-community-sendcoins-transactions_table',
+ DB_VERSION: '0067-private_key_in_community_table',
LOG4JS_CONFIG: 'log4js-config.json',
// default log level on production should be info
LOG_LEVEL: process.env.LOG_LEVEL || 'info',
diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts
index 004fc816e..a767c323e 100644
--- a/dht-node/src/dht_node/index.ts
+++ b/dht-node/src/dht_node/index.ts
@@ -24,6 +24,8 @@ type CommunityApi = {
url: string
}
+type KeyPair = { publicKey: Buffer; secretKey: Buffer }
+
export const startDHT = async (topic: string): Promise => {
try {
const TOPIC = DHT.hash(Buffer.from(topic))
@@ -32,11 +34,11 @@ export const startDHT = async (topic: string): Promise => {
CONFIG.FEDERATION_DHT_SEED
? Buffer.alloc(KEY_SECRET_SEEDBYTES, CONFIG.FEDERATION_DHT_SEED)
: null,
- )
+ ) as KeyPair
const pubKeyString = keyPair.publicKey.toString('hex')
logger.info(`keyPairDHT: publicKey=${pubKeyString}`)
logger.debug(`keyPairDHT: secretKey=${keyPair.secretKey.toString('hex')}`)
- await writeHomeCommunityEntry(pubKeyString)
+ await writeHomeCommunityEntry(keyPair)
const ownApiVersions = await writeFederatedHomeCommunityEntries(pubKeyString)
logger.info(`ApiList: ${JSON.stringify(ownApiVersions)}`)
@@ -212,13 +214,14 @@ async function writeFederatedHomeCommunityEntries(pubKey: string): Promise {
+async function writeHomeCommunityEntry(keyPair: KeyPair): Promise {
try {
// check for existing homeCommunity entry
let homeCom = await DbCommunity.findOne({ foreign: false })
if (homeCom) {
// simply update the existing entry, but it MUST keep the ID and UUID because of possible relations
- homeCom.publicKey = Buffer.from(pubKey)
+ homeCom.publicKey = keyPair.publicKey
+ homeCom.privateKey = keyPair.secretKey
homeCom.url = CONFIG.FEDERATION_COMMUNITY_URL + '/api/'
homeCom.name = CONFIG.COMMUNITY_NAME
homeCom.description = CONFIG.COMMUNITY_DESCRIPTION
@@ -228,7 +231,8 @@ async function writeHomeCommunityEntry(pubKey: string): Promise {
// insert a new homecommunity entry including a new ID and a new but ensured unique UUID
homeCom = new DbCommunity()
homeCom.foreign = false
- homeCom.publicKey = Buffer.from(pubKey)
+ homeCom.publicKey = keyPair.publicKey
+ homeCom.privateKey = keyPair.secretKey
homeCom.communityUuid = await newCommunityUuid()
homeCom.url = CONFIG.FEDERATION_COMMUNITY_URL + '/api/'
homeCom.name = CONFIG.COMMUNITY_NAME
diff --git a/dht-node/src/index.ts b/dht-node/src/index.ts
index d5e5f700b..e70b324b5 100644
--- a/dht-node/src/index.ts
+++ b/dht-node/src/index.ts
@@ -33,5 +33,5 @@ async function main() {
main().catch((e) => {
// eslint-disable-next-line no-console
console.error(e)
- process.exit(1)
+ throw e
})
diff --git a/federation/src/config/index.ts b/federation/src/config/index.ts
index 710248472..b44487aa9 100644
--- a/federation/src/config/index.ts
+++ b/federation/src/config/index.ts
@@ -11,7 +11,7 @@ Decimal.set({
*/
const constants = {
- DB_VERSION: '0066-x-community-sendcoins-transactions_table',
+ DB_VERSION: '0067-private_key_in_community_table',
// DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
LOG4JS_CONFIG: 'log4js-config.json',
// default log level on production should be info
diff --git a/frontend/public/img/brand/gradido-email-header.png b/frontend/public/img/brand/gradido-email-header.png
new file mode 100644
index 000000000..b7fa83b92
Binary files /dev/null and b/frontend/public/img/brand/gradido-email-header.png differ
diff --git a/frontend/src/assets/News/news.json b/frontend/src/assets/News/news.json
index 9246be2e3..e10bcc890 100644
--- a/frontend/src/assets/News/news.json
+++ b/frontend/src/assets/News/news.json
@@ -1,37 +1,37 @@
[
{
"locale": "de",
- "date": "01. Januar 2023",
- "text": "Gradido-Konto 2023: neues Design und dezentrale Communities",
- "url": "https://gradido.net/de/gradido-konto-2023-neues-design-und-dezentrale-communities/",
- "extra": "Oft sind es die leiseren Menschen, die still, fleißig und mit Herzblut die Grundlagen für großartige Entwicklungen schaffen. Unsere Entwickler haben in den vergangenen Monaten großartige Vorarbeiten gemacht, die im Jahr 2023 zum Tragen kommen werden."
+ "date": "13. juni 2023",
+ "text": "Neue Funktion verfügbar: Jetzt Benutzernamen eintragen!",
+ "url": "/settings",
+ "extra": "Deine persönlichen Daten sind uns wichtig, und wir legen großen Wert auf deren Schutz. Wir wissen, dass nicht jeder seine E-Mail-Adresse anderen Benutzern preisgeben möchte. Aus diesem Grund kannst du nun einen Benutzernamen deiner Wahl in den Einstellungen angeben. Dies ist auch ein wichtiger Bestandteil unserer Vorbereitung für die bevorstehende Einführung unserer dezentralen Community-Server."
},
{
"locale": "en",
- "date": "01 January 2023",
- "text": "Gradido account 2023: new design and decentralized communities",
- "url": "https://gradido.net/en/gradido-konto-2023-neues-design-und-dezentrale-communities/",
- "extra": "It is often the quieter people who quietly, diligently and with heart and soul create the foundations for great developments. Our Developer have done great preparatory work in recent months that will come to fruition in 2023."
+ "date": "13 june 2023",
+ "text": "New function available: Enter username now!",
+ "url": "/settings",
+ "extra": "Your personal information is important to us, and we take great care to protect it. We know that not everyone wants to reveal their email address to other users. For this reason, you can now enter a username of your choice in the settings. This is also an important part of our preparation for the upcoming launch of our decentralized community servers."
},
{
"locale": "fr",
- "date": "01 janvier 2023",
- "text": "Compte Gradido 2023 : nouveau design et communautés décentralisées",
- "url": "https://gradido.net/fr/gradido-konto-2023-neues-design-und-dezentrale-communities/",
- "extra": "Ce sont souvent les personnes les plus discrètes qui créent silencieusement, avec application et passion, les bases de grands développements. Nos développeurs ont effectués ces derniers mois un travail préparatoire formidable qui sera mis à profit en 2023."
+ "date": "13 juin 2023",
+ "text": "Nouvelle fonction disponible : Saisis ton nom d'utilisateur maintenant !",
+ "url": "/settings",
+ "extra": "Tes données personnelles sont importantes pour nous et nous attachons une grande importance à leur protection. Nous savons que certains ne souhaitent pas divulguer leur adresse e-mail à d'autres utilisateurs. C'est pourquoi tu peux désormais indiquer un nom d'utilisateur de ton choix dans les paramètres. Il s'agit également d'un élément important de notre préparation à l'introduction prochaine de nos serveurs communautaires décentralisés."
},
{
"locale": "es",
- "date": "01 de enero de 20233",
- "text": "Cuenta Gradido 2023: nuevo diseño y comunidades descentralizadas",
- "url": "https://gradido.net/es/gradido-konto-2023-neues-design-und-dezentrale-communities/",
- "extra": "A menudo son las personas más calladas las que, en silencio, con diligencia y con el corazón y el alma, crean los cimientos de los grandes avances. Nuestra Desarrollador han realizado un gran trabajo preparatorio en los últimos meses, que dará sus frutos en 2023."
+ "date": "13 junio 20233",
+ "text": "Nueva función disponible: Introduzca ahora su nombre de usuario",
+ "url": "/settings",
+ "extra": "Sus datos personales son importantes para nosotros y concedemos gran importancia a su protección. Sabemos que no todo el mundo quiere revelar su dirección de correo electrónico a otros usuarios. Por este motivo, ahora puede introducir un nombre de usuario de su elección en los ajustes. Esto es también una parte importante de nuestra preparación para el próximo lanzamiento de nuestros servidores comunitarios descentralizados."
},
{
"locale": "nl",
- "date": "01 januari 2023",
- "text": "Gradidorekening 2023: nieuw ontwerp en gedecentraliseerde gemeenschappen",
- "url": "https://gradido.net/nl/gradido-konto-2023-neues-design-und-dezentrale-communities/",
- "extra": "Het zijn vaak de stillere mensen die stilletjes, ijverig en met hart en ziel de basis leggen voor grote ontwikkelingen. Onze Ontwikkelaar hebben de afgelopen maanden veel voorbereidend werk gedaan, dat in 2023 zijn vruchten zal afwerpen."
+ "date": "13 juni 2023",
+ "text": "Nieuwe functie beschikbaar: Voer nu je gebruikersnaam in!",
+ "url": "/settings",
+ "extra": "Je persoonlijke gegevens zijn belangrijk voor ons en we hechten veel belang aan de bescherming ervan. We weten dat niet iedereen zijn e-mailadres bekend wil maken aan andere gebruikers. Daarom kun je nu een gebruikersnaam naar keuze invoeren in de instellingen. Dit is ook een belangrijk onderdeel van onze voorbereiding op de komende lancering van onze gedecentraliseerde community servers."
}
]
diff --git a/frontend/src/components/Overview/CommunityNews.vue b/frontend/src/components/Overview/CommunityNews.vue
index e06f3c431..e1382cbfa 100644
--- a/frontend/src/components/Overview/CommunityNews.vue
+++ b/frontend/src/components/Overview/CommunityNews.vue
@@ -19,8 +19,8 @@
-
- {{ $t('auth.left.learnMore') }}
+
+ {{ $t('community.startNewsButton') }}
diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json
index bc125bc7e..ab93bed85 100644
--- a/frontend/src/locales/de.json
+++ b/frontend/src/locales/de.json
@@ -30,6 +30,7 @@
"noOpenContributionLinkText": "Zur Zeit gibt es keine per Link erzeugte Schöpfungen.",
"openContributionLinks": "Per Link erzeugte Schöpfungen",
"openContributionLinkText": "Die Gemeinschaft „{name}“ unterstützt aktuell {count} per Link erzeugte Schöpfungen:",
+ "startNewsButton": "Benutzernamen eintragen",
"submitContribution": "Schreiben"
},
"communityInfo": "Gemeinschaft Information",
diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json
index 6b779613d..ed0836e29 100644
--- a/frontend/src/locales/en.json
+++ b/frontend/src/locales/en.json
@@ -30,6 +30,7 @@
"noOpenContributionLinkText": "Currently there are no link-generated creations.",
"openContributionLinks": "Creations generated by link",
"openContributionLinkText": "The \"{name}\" community currently supports {count} link-generated creations:",
+ "startNewsButton": "Enter username",
"submitContribution": "Contribute"
},
"communityInfo": "Community Information",
diff --git a/frontend/src/locales/es.json b/frontend/src/locales/es.json
index 725eb10ad..9c702619f 100644
--- a/frontend/src/locales/es.json
+++ b/frontend/src/locales/es.json
@@ -30,6 +30,7 @@
"openContributionLinks": "Creaciones generadas por enlace",
"openContributionLinkText": "La comunidad \"{name}\" admite actualmente {count} creaciones generadas por enlaces:",
"other-communities": "Otras comunidades",
+ "startNewsButton": "Introducir nombre de usuario",
"statistic": "Estadísticas",
"submitContribution": "escribir",
"switch-to-this-community": "cambiar a esta comunidad"
diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json
index 5765b0746..45607289b 100644
--- a/frontend/src/locales/fr.json
+++ b/frontend/src/locales/fr.json
@@ -30,6 +30,7 @@
"noOpenContributionLinkText": "Actuellement, il n'y a pas de créations générées par lien.",
"openContributionLinks": "Créations générées par lien",
"openContributionLinkText": "La communauté \"{name}\" soutient actuellement {count} créations générées par lien:",
+ "startNewsButton": "Saisir nom d'utilisateur",
"submitContribution": "Contribuer"
},
"communityInfo": "Information communauté^^",
diff --git a/frontend/src/locales/nl.json b/frontend/src/locales/nl.json
index f1306eda8..2e6217841 100644
--- a/frontend/src/locales/nl.json
+++ b/frontend/src/locales/nl.json
@@ -30,6 +30,7 @@
"openContributionLinks": "Creaties gegenereerd door link",
"openContributionLinkText": "De community \"{name}\" ondersteunt momenteel {count} link-gegenereerde creaties:",
"other-communities": "Verdere gemeenschappen",
+ "startNewsButton": "Gebruikersnaam invoeren",
"statistic": "Statistieken",
"submitContribution": "schrijf",
"switch-to-this-community": "naar deze gemeenschap wisselen"
diff --git a/frontend/src/locales/tr.json b/frontend/src/locales/tr.json
index 4bfc7145b..610a7d149 100644
--- a/frontend/src/locales/tr.json
+++ b/frontend/src/locales/tr.json
@@ -26,6 +26,7 @@
"current-community": "Varolan topluluk",
"myContributions": "Toplum yararına yaptığım hizmetler",
"other-communities": "Diğer topluluklar",
+ "startNewsButton": "Kullanıcı adı girin",
"submitContribution": "yaz",
"switch-to-this-community": "Bu topluluğa giriş yap"
},
diff --git a/frontend/src/pages/Login.vue b/frontend/src/pages/Login.vue
index 6fd435c2d..6e0a50949 100644
--- a/frontend/src/pages/Login.vue
+++ b/frontend/src/pages/Login.vue
@@ -86,6 +86,7 @@ export default {
const loader = this.$loading.show({
container: this.$refs.submitButton,
})
+ this.$root.$bvToast.hide()
this.$apollo
.mutate({
mutation: login,