diff --git a/.gitignore b/.gitignore index a75e9805d..08ccd2b30 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,9 @@ package-lock.json /deployment/bare_metal/nginx/update-page/updating.html /deployment/bare_metal/log /deployment/bare_metal/backup -/.nvmrc + +# Node Version Manager configuration file +.nvmrc + +# Apple macOS folder attribute file +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e8e748af..48eeff9a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,30 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.8.3](https://github.com/gradido/gradido/compare/1.8.2...1.8.3) + +- Checkbox [`#1894`](https://github.com/gradido/gradido/pull/1894) +- fix: Count Deprecated Links as Well [`#1892`](https://github.com/gradido/gradido/pull/1892) + +#### [1.8.2](https://github.com/gradido/gradido/compare/1.8.1...1.8.2) + +> 12 May 2022 + +- Release 1.8.2 [`#1890`](https://github.com/gradido/gradido/pull/1890) +- Update README.md [`#1878`](https://github.com/gradido/gradido/pull/1878) +- fix: Unique Previous Column in Transactions Table [`#1879`](https://github.com/gradido/gradido/pull/1879) +- fix: Up and Down Migrations for Older SQL Versions [`#1861`](https://github.com/gradido/gradido/pull/1861) +- 🍰 Refactor THX Page – 1. Step [`#1856`](https://github.com/gradido/gradido/pull/1856) +- Create LICENSE [`#1803`](https://github.com/gradido/gradido/pull/1803) +- docu: Update Deployment Documentation [`#1864`](https://github.com/gradido/gradido/pull/1864) +- fix: Loading Transaction Links after Reopening Link List [`#1863`](https://github.com/gradido/gradido/pull/1863) +- 🍰 Add NVM Config Files To '.gitignore' [`#1846`](https://github.com/gradido/gradido/pull/1846) + #### [1.8.1](https://github.com/gradido/gradido/compare/1.8.0...1.8.1) +> 28 April 2022 + +- v1.8.1 [`#1855`](https://github.com/gradido/gradido/pull/1855) - 1851 integrate and test the behaviour of clipboard polyfill [`#1853`](https://github.com/gradido/gradido/pull/1853) - fix: Deprecated Warning from Faker on Seeding [`#1854`](https://github.com/gradido/gradido/pull/1854) - feat: Test Admin Resolver [`#1848`](https://github.com/gradido/gradido/pull/1848) diff --git a/README.md b/README.md index e97055a78..2911c13d3 100644 --- a/README.md +++ b/README.md @@ -93,3 +93,15 @@ Note: The Changelog will be regenerated with all tags on release on the external ## Useful Links - [Gradido.net](https://gradido.net/) + + +## Attributions + +![browserstack_logo-freelogovectors net_](https://user-images.githubusercontent.com/1324583/167782608-0e4db0d4-3d34-45fb-ab06-344aa5e5ef4b.png) + +Browser compatibility testing with [BrowserStack](https://www.browserstack.com/). + + +## License +See the [LICENSE](LICENSE.md) file for license rights and limitations (Apache-2.0 license). + diff --git a/admin/.gitignore b/admin/.gitignore index d78b066c1..a67d270bc 100644 --- a/admin/.gitignore +++ b/admin/.gitignore @@ -10,4 +10,3 @@ coverage/ # emacs *~ -/.nvmrc diff --git a/admin/package.json b/admin/package.json index 1ff6de770..57711b8be 100644 --- a/admin/package.json +++ b/admin/package.json @@ -3,7 +3,7 @@ "description": "Administraion Interface for Gradido", "main": "index.js", "author": "Moriz Wahl", - "version": "1.8.1", + "version": "1.8.3", "license": "MIT", "private": false, "scripts": { diff --git a/backend/.gitignore b/backend/.gitignore index 2381e9abc..6eadcc884 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -6,4 +6,3 @@ package-json.lock coverage # emacs *~ -/.nvmrc diff --git a/backend/package.json b/backend/package.json index f46572f3c..678e3578a 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "gradido-backend", - "version": "1.8.1", + "version": "1.8.3", "description": "Gradido unified backend providing an API-Service for Gradido Transactions", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/backend", diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 057ee455e..559b8e9c5 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0035-admin_pending_creations_decimal', + DB_VERSION: '0036-unique_previous_in_transactions', DECAY_START_TIME: new Date('2021-05-13 17:46:31'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index 8bb22f87e..c0245cdfd 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -1077,6 +1077,53 @@ describe('AdminResolver', () => { expect(transaction[0].typeId).toEqual(1) }) }) + + describe('confirm two creations one after the other quickly', () => { + let c1: AdminPendingCreation | void + let c2: AdminPendingCreation | void + + beforeAll(async () => { + const now = new Date() + c1 = await creationFactory(testEnv, { + email: 'bibi@bloxberg.de', + amount: 50, + memo: 'Herzlich Willkommen bei Gradido liebe Bibi!', + creationDate: new Date(now.getFullYear(), now.getMonth() - 2, 1).toISOString(), + }) + c2 = await creationFactory(testEnv, { + email: 'bibi@bloxberg.de', + amount: 50, + memo: 'Herzlich Willkommen bei Gradido liebe Bibi!', + creationDate: new Date(now.getFullYear(), now.getMonth() - 2, 1).toISOString(), + }) + }) + + // In the futrue this should not throw anymore + it('throws an error for the second confirmation', async () => { + const r1 = mutate({ + mutation: confirmPendingCreation, + variables: { + id: c1 ? c1.id : -1, + }, + }) + const r2 = mutate({ + mutation: confirmPendingCreation, + variables: { + id: c2 ? c2.id : -1, + }, + }) + await expect(r1).resolves.toEqual( + expect.objectContaining({ + data: { confirmPendingCreation: true }, + }), + ) + await expect(r2).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Unable to confirm creation.')], + }), + ) + }) + }) }) }) }) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 78cbf3fc8..8da92a61c 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -361,7 +361,9 @@ export class AdminResolver { transaction.balanceDate = receivedCallDate transaction.decay = decay ? decay.decay : new Decimal(0) transaction.decayStart = decay ? decay.start : null - await transaction.save() + await transaction.save().catch(() => { + throw new Error('Unable to confirm creation.') + }) await AdminPendingCreation.delete(pendingCreation) diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 8aa4d24d7..a7d873ba8 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -9,7 +9,7 @@ import { Transaction as dbTransaction } from '@entity/Transaction' import Decimal from 'decimal.js-light' import { GdtResolver } from './GdtResolver' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' -import { MoreThan, getCustomRepository } from '@dbTools/typeorm' +import { getCustomRepository } from '@dbTools/typeorm' import { TransactionLinkRepository } from '@repository/TransactionLink' const logger = getLogger('backend') @@ -52,16 +52,13 @@ export class BalanceResolver { : await dbTransaction.count({ where: { userId: user.id } }) logger.debug(`transactionCount=${count}`) - const linkCount = - context.linkCount || context.linkCount === 0 - ? context.linkCount - : await dbTransactionLink.count({ - where: { - userId: user.id, - redeemedAt: null, - validUntil: MoreThan(new Date()), - }, - }) + const linkCount = await dbTransactionLink.count({ + where: { + userId: user.id, + redeemedAt: null, + // validUntil: MoreThan(new Date()), + }, + }) logger.debug(`linkCount=${linkCount}`) // The decay is always calculated on the last booked transaction diff --git a/backend/src/seeds/creation/index.ts b/backend/src/seeds/creation/index.ts index 20d30d94c..38cb98361 100644 --- a/backend/src/seeds/creation/index.ts +++ b/backend/src/seeds/creation/index.ts @@ -1,6 +1,131 @@ import { CreationInterface } from './CreationInterface' import { nMonthsBefore } from '../factory/creation' +const bobsSendings = [ + { + amount: 10, + memo: 'Herzlich Willkommen bei Gradido!', + }, + { + amount: 10, + memo: 'für deine Hilfe, Betty', + }, + { + amount: 23.37, + memo: 'für deine Hilfe, David', + }, + { + amount: 47, + memo: 'für deine Hilfe, Frau Holle', + }, + { + amount: 1.02, + memo: 'für deine Hilfe, Herr Müller', + }, + { + amount: 5.67, + memo: 'für deine Hilfe, Maier', + }, + { + amount: 72.93, + memo: 'für deine Hilfe, Elsbeth', + }, + { + amount: 5.6, + memo: 'für deine Hilfe, Daniel', + }, + { + amount: 8.87, + memo: 'für deine Hilfe, Yoda', + }, + { + amount: 7.56, + memo: 'für deine Hilfe, Sabine', + }, + { + amount: 7.89, + memo: 'für deine Hilfe, Karl', + }, + { + amount: 8.9, + memo: 'für deine Hilfe, Darth Vader', + }, + { + amount: 56.79, + memo: 'für deine Hilfe, Luci', + }, + { + amount: 3.45, + memo: 'für deine Hilfe, Hanne', + }, + { + amount: 8.74, + memo: 'für deine Hilfe, Luise', + }, + { + amount: 7.85, + memo: 'für deine Hilfe, Annegred', + }, + { + amount: 32.7, + memo: 'für deine Hilfe, Prinz von Zamunda', + }, + { + amount: 44.2, + memo: 'für deine Hilfe, Charly Brown', + }, + { + amount: 38.17, + memo: 'für deine Hilfe, Michael', + }, + { + amount: 5.72, + memo: 'für deine Hilfe, Kaja', + }, + { + amount: 3.99, + memo: 'für deine Hilfe, Maja', + }, + { + amount: 4.5, + memo: 'für deine Hilfe, Martha', + }, + { + amount: 8.3, + memo: 'für deine Hilfe, Ursula', + }, + { + amount: 2.9, + memo: 'für deine Hilfe, Urs', + }, + { + amount: 4.6, + memo: 'für deine Hilfe, Mecedes', + }, + { + amount: 74.1, + memo: 'für deine Hilfe, Heidi', + }, + { + amount: 4.5, + memo: 'für deine Hilfe, Peter', + }, + { + amount: 5.8, + memo: 'für deine Hilfe, Fräulein Rottenmeier', + }, +] +const bobsTransactions: CreationInterface[] = [] +bobsSendings.forEach((sending) => { + bobsTransactions.push({ + email: 'bob@baumeister.de', + amount: sending.amount, + memo: sending.memo, + creationDate: nMonthsBefore(new Date()), + confirmed: true, + }) +}) + export const creations: CreationInterface[] = [ { email: 'bibi@bloxberg.de', @@ -10,14 +135,7 @@ export const creations: CreationInterface[] = [ confirmed: true, moveCreationDate: 12, }, - { - email: 'bob@baumeister.de', - amount: 1000, - memo: 'Herzlich Willkommen bei Gradido!', - creationDate: nMonthsBefore(new Date()), - confirmed: true, - moveCreationDate: 8, - }, + ...bobsTransactions, { email: 'raeuber@hotzenplotz.de', amount: 1000, diff --git a/backend/src/seeds/index.ts b/backend/src/seeds/index.ts index f26000e06..21539e1ba 100644 --- a/backend/src/seeds/index.ts +++ b/backend/src/seeds/index.ts @@ -66,7 +66,10 @@ const run = async () => { // create GDD for (let i = 0; i < creations.length; i++) { + const now = new Date().getTime() // we have to wait a little! quick fix for account sum problem of bob@baumeister.de, (see https://github.com/gradido/gradido/issues/1886) await creationFactory(seedClient, creations[i]) + // eslint-disable-next-line no-empty + while (new Date().getTime() < now + 1000) {} // we have to wait a little! quick fix for account sum problem of bob@baumeister.de, (see https://github.com/gradido/gradido/issues/1886) } // create Transaction Links diff --git a/database/.gitignore b/database/.gitignore index d1bd69ed3..9e9e01ced 100644 --- a/database/.gitignore +++ b/database/.gitignore @@ -25,4 +25,3 @@ package-lock.json coverage/ *~ -/.nvmrc diff --git a/database/entity/0036-unique_previous_in_transactions/Transaction.ts b/database/entity/0036-unique_previous_in_transactions/Transaction.ts new file mode 100644 index 000000000..99202eee4 --- /dev/null +++ b/database/entity/0036-unique_previous_in_transactions/Transaction.ts @@ -0,0 +1,94 @@ +import Decimal from 'decimal.js-light' +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' +import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' + +@Entity('transactions') +export class Transaction extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ name: 'user_id', unsigned: true, nullable: false }) + userId: number + + @Column({ type: 'int', unsigned: true, unique: true, nullable: true, default: null }) + previous: number | null + + @Column({ name: 'type_id', unsigned: true, nullable: false }) + typeId: number + + @Column({ + type: 'decimal', + precision: 40, + scale: 20, + nullable: false, + transformer: DecimalTransformer, + }) + amount: Decimal + + @Column({ + type: 'decimal', + precision: 40, + scale: 20, + nullable: false, + transformer: DecimalTransformer, + }) + balance: Decimal + + @Column({ + name: 'balance_date', + type: 'datetime', + default: () => 'CURRENT_TIMESTAMP', + nullable: false, + }) + balanceDate: Date + + @Column({ + type: 'decimal', + precision: 40, + scale: 20, + nullable: false, + transformer: DecimalTransformer, + }) + decay: Decimal + + @Column({ + name: 'decay_start', + type: 'datetime', + nullable: true, + default: null, + }) + decayStart: Date | null + + @Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' }) + memo: string + + @Column({ name: 'creation_date', type: 'datetime', nullable: true, default: null }) + creationDate: Date | null + + @Column({ + name: 'linked_user_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + linkedUserId?: number | null + + @Column({ + name: 'linked_transaction_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + linkedTransactionId?: number | null + + @Column({ + name: 'transaction_link_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + transactionLinkId?: number | null +} diff --git a/database/entity/Transaction.ts b/database/entity/Transaction.ts index 3515202d0..5365b0f70 100644 --- a/database/entity/Transaction.ts +++ b/database/entity/Transaction.ts @@ -1 +1 @@ -export { Transaction } from './0032-add-transaction-link-to-transaction/Transaction' +export { Transaction } from './0036-unique_previous_in_transactions/Transaction' diff --git a/database/migrations/0036-unique_previous_in_transactions.ts b/database/migrations/0036-unique_previous_in_transactions.ts new file mode 100644 index 000000000..f05b044bb --- /dev/null +++ b/database/migrations/0036-unique_previous_in_transactions.ts @@ -0,0 +1,13 @@ +/* MIGRATION TO SET previous COLUMN UNIQUE in TRANSACTION 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 `transactions` ADD UNIQUE(`previous`);') +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn('ALTER TABLE `transactions` DROP INDEX `previous`;') +} diff --git a/database/package.json b/database/package.json index a19cc57da..f5a16fd31 100644 --- a/database/package.json +++ b/database/package.json @@ -1,6 +1,6 @@ { "name": "gradido-database", - "version": "1.8.1", + "version": "1.8.3", "description": "Gradido Database Tool to execute database migrations", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/database", diff --git a/docu/Style/Images/Checkbox_aktiv.svg b/docu/Style/Images/Checkbox_aktiv.svg new file mode 100644 index 000000000..3ee7c1b24 --- /dev/null +++ b/docu/Style/Images/Checkbox_aktiv.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docu/Style/Images/Checkbox_deaktiv.svg b/docu/Style/Images/Checkbox_deaktiv.svg new file mode 100644 index 000000000..4770d4b33 --- /dev/null +++ b/docu/Style/Images/Checkbox_deaktiv.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/.gitignore b/frontend/.gitignore index 2054a5cd5..0a541ba06 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -24,4 +24,3 @@ package-lock.json coverage/ *~ -/.nvmrc diff --git a/frontend/package.json b/frontend/package.json index 7b448a73d..9d70ace58 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "bootstrap-vue-gradido-wallet", - "version": "1.8.1", + "version": "1.8.3", "private": true, "scripts": { "start": "node run/server.js", diff --git a/frontend/public/img/brand/gradido_coin●.png b/frontend/public/img/brand/gradido_coin●.png new file mode 100644 index 000000000..15a5182da Binary files /dev/null and b/frontend/public/img/brand/gradido_coin●.png differ diff --git a/frontend/public/img/svg/type.svg b/frontend/public/img/svg/type.svg new file mode 100644 index 000000000..9ab1e4c48 --- /dev/null +++ b/frontend/public/img/svg/type.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/public/img/template/Blaetter.png b/frontend/public/img/template/Blaetter.png new file mode 100644 index 000000000..af11b67f2 Binary files /dev/null and b/frontend/public/img/template/Blaetter.png differ diff --git a/frontend/public/img/template/Foto_01.jpg b/frontend/public/img/template/Foto_01.jpg new file mode 100644 index 000000000..3e64e27a5 Binary files /dev/null and b/frontend/public/img/template/Foto_01.jpg differ diff --git a/frontend/public/img/template/gold_03.png b/frontend/public/img/template/gold_03.png new file mode 100644 index 000000000..0704c997a Binary files /dev/null and b/frontend/public/img/template/gold_03.png differ diff --git a/frontend/public/img/template/gradido_background_header.png b/frontend/public/img/template/gradido_background_header.png new file mode 100644 index 000000000..db651686f Binary files /dev/null and b/frontend/public/img/template/gradido_background_header.png differ diff --git a/frontend/public/img/template/logo-header.png b/frontend/public/img/template/logo-header.png new file mode 100644 index 000000000..b35dda73d Binary files /dev/null and b/frontend/public/img/template/logo-header.png differ diff --git a/frontend/src/components/GddTransactionList.spec.js b/frontend/src/components/GddTransactionList.spec.js index 37152c1c2..a6d0ef935 100644 --- a/frontend/src/components/GddTransactionList.spec.js +++ b/frontend/src/components/GddTransactionList.spec.js @@ -407,29 +407,34 @@ describe('GddTransactionList', () => { }) describe('pagination buttons', () => { + const createTransaction = (idx) => { + return { + amount: '3.14', + balanceDate: '2021-04-29T17:26:40+00:00', + decay: { + decay: '-477.01', + start: '2021-05-13T17:46:31.000Z', + end: '2022-04-20T06:51:25.000Z', + duration: 29509494, + }, + memo: 'Kreiszahl PI', + linkedUser: { + firstName: 'Bibi', + lastName: 'Bloxberg', + }, + id: idx + 1, + typeId: 'RECEIVE', + balance: '33.33', + } + } + beforeEach(async () => { + const transactionCount = 42 await wrapper.setProps({ - transactions: Array.from({ length: 42 }, (_, idx) => { - return { - amount: '3.14', - balanceDate: '2021-04-29T17:26:40+00:00', - decay: { - decay: '-477.01', - start: '2021-05-13T17:46:31.000Z', - end: '2022-04-20T06:51:25.000Z', - duration: 29509494, - }, - memo: 'Kreiszahl PI', - linkedUser: { - firstName: 'Bibi', - lastName: 'Bloxberg', - }, - id: idx + 1, - typeId: 'RECEIVE', - balance: '33.33', - } + transactions: Array.from({ length: transactionCount }, (_, idx) => { + return createTransaction(idx) }), - transactionCount: 42, + transactionCount, decayStartBlock, pageSize: 25, showPagination: true, @@ -449,22 +454,22 @@ describe('GddTransactionList', () => { ) }) }) - }) - describe('show no pagination', () => { - beforeEach(async () => { - await wrapper.setProps({ - transactions: [], - transactionCount: 2, - decayStartBlock, - pageSize: 25, - showPagination: false, + describe('show no pagination', () => { + it('shows no pagination buttons', async () => { + const transactionCount = 2 + await wrapper.setProps({ + transactions: Array.from({ length: transactionCount }, (_, idx) => { + return createTransaction(idx) + }), + transactionCount, + decayStartBlock, + pageSize: 25, + showPagination: false, + }) + expect(wrapper.find('ul.pagination').exists()).toBe(false) }) }) - - it('shows no pagination buttons', () => { - expect(wrapper.find('ul.pagination').exists()).toBe(false) - }) }) }) }) diff --git a/frontend/src/components/GddTransactionList.vue b/frontend/src/components/GddTransactionList.vue index 34f7c24ab..5becfa39e 100644 --- a/frontend/src/components/GddTransactionList.vue +++ b/frontend/src/components/GddTransactionList.vue @@ -61,7 +61,7 @@ [] }, pageSize: { type: Number, default: 25 }, @@ -110,6 +105,11 @@ export default { showPagination: { type: Boolean, default: false }, pending: { type: Boolean }, }, + data() { + return { + currentPage: 1, + } + }, methods: { updateTransactions() { this.$emit('update-transactions', { @@ -123,6 +123,11 @@ export default { return '0' }, }, + computed: { + isPaginationVisible() { + return this.showPagination && this.pageSize < this.transactionCount + }, + }, watch: { currentPage() { this.updateTransactions() @@ -134,6 +139,7 @@ export default { }, } +