diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index ea3b5c19e..8d1ed8ae6 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -12,7 +12,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0065-refactor_communities_table', + DB_VERSION: '0066-x-community-sendcoins-transactions_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/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index d2203dac3..fa1590523 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -43,6 +43,7 @@ import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { calculateDecay } from '@/util/decay' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' +import { fullName } from '@/util/utilities' import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { @@ -500,6 +501,8 @@ export class ContributionResolver { transaction.typeId = TransactionTypeId.CREATION transaction.memo = contribution.memo transaction.userId = contribution.userId + transaction.userGradidoID = user.gradidoID + transaction.userName = fullName(user.firstName, user.lastName) transaction.previous = lastTransaction ? lastTransaction.id : null transaction.amount = contribution.amount transaction.creationDate = contribution.contributionDate diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index ca638d0be..d6649814a 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -34,6 +34,7 @@ import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { calculateDecay } from '@/util/decay' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' +import { fullName } from '@/util/utilities' import { calculateBalance } from '@/util/validate' import { executeTransaction } from './TransactionResolver' @@ -266,6 +267,8 @@ export class TransactionLinkResolver { transaction.typeId = TransactionTypeId.CREATION transaction.memo = contribution.memo transaction.userId = contribution.userId + transaction.userGradidoID = user.gradidoID + transaction.userName = fullName(user.firstName, user.lastName) transaction.previous = lastTransaction ? lastTransaction.id : null transaction.amount = contribution.amount transaction.creationDate = contribution.contributionDate diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 80c8be070..3c540b1f6 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -29,6 +29,7 @@ import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { communityUser } from '@/util/communityUser' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' +import { fullName } from '@/util/utilities' import { calculateBalance } from '@/util/validate' import { virtualLinkTransaction, virtualDecayTransaction } from '@/util/virtualTransactions' @@ -85,7 +86,11 @@ export const executeTransaction = async ( transactionSend.typeId = TransactionTypeId.SEND transactionSend.memo = memo transactionSend.userId = sender.id + transactionSend.userGradidoID = sender.gradidoID + transactionSend.userName = fullName(sender.firstName, sender.lastName) transactionSend.linkedUserId = recipient.id + transactionSend.linkedUserGradidoID = recipient.gradidoID + transactionSend.linkedUserName = fullName(recipient.firstName, recipient.lastName) transactionSend.amount = amount.mul(-1) transactionSend.balance = sendBalance.balance transactionSend.balanceDate = receivedCallDate @@ -101,7 +106,11 @@ export const executeTransaction = async ( transactionReceive.typeId = TransactionTypeId.RECEIVE transactionReceive.memo = memo transactionReceive.userId = recipient.id + transactionReceive.userGradidoID = recipient.gradidoID + transactionReceive.userName = fullName(recipient.firstName, recipient.lastName) transactionReceive.linkedUserId = sender.id + transactionReceive.linkedUserGradidoID = sender.gradidoID + transactionReceive.linkedUserName = fullName(sender.firstName, sender.lastName) transactionReceive.amount = amount const receiveBalance = await calculateBalance(recipient.id, amount, receivedCallDate) transactionReceive.balance = receiveBalance ? receiveBalance.balance : amount diff --git a/backend/src/util/utilities.ts b/backend/src/util/utilities.ts index d5da55aed..904c86226 100644 --- a/backend/src/util/utilities.ts +++ b/backend/src/util/utilities.ts @@ -12,3 +12,6 @@ export const decimalSeparatorByLanguage = (a: Decimal, language: string): string i18n.setLocale(rememberLocaleToRestore) return result } + +export const fullName = (firstName: string, lastName: string): string => + [firstName, lastName].filter(Boolean).join(' ') diff --git a/backend/src/util/virtualTransactions.ts b/backend/src/util/virtualTransactions.ts index 5d1fbbfd3..a10e566d1 100644 --- a/backend/src/util/virtualTransactions.ts +++ b/backend/src/util/virtualTransactions.ts @@ -54,6 +54,10 @@ const virtualLinkTransaction = ( creationDate: null, contribution: null, ...defaultModelFunctions, + userGradidoID: '', + userName: null, + linkedUserGradidoID: null, + linkedUserName: null, } return new Transaction(linkDbTransaction, user) } @@ -84,6 +88,10 @@ const virtualDecayTransaction = ( creationDate: null, contribution: null, ...defaultModelFunctions, + userGradidoID: '', + userName: null, + linkedUserGradidoID: null, + linkedUserName: null, } return new Transaction(decayDbTransaction, user) } diff --git a/database/entity/0066-x-community-sendcoins-transactions_table/Transaction.ts b/database/entity/0066-x-community-sendcoins-transactions_table/Transaction.ts new file mode 100644 index 000000000..4220cfadc --- /dev/null +++ b/database/entity/0066-x-community-sendcoins-transactions_table/Transaction.ts @@ -0,0 +1,139 @@ +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' + +@Entity('transactions') +export class Transaction extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: 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({ + name: 'transaction_link_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + transactionLinkId?: number | null + + @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: 'user_id', unsigned: true, nullable: false }) + userId: number + + @Column({ + name: 'user_gradido_id', + type: 'varchar', + length: 36, + nullable: false, + collation: 'utf8mb4_unicode_ci', + }) + userGradidoID: string + + @Column({ + name: 'user_name', + type: 'varchar', + length: 512, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + userName: string | null + + @Column({ + name: 'linked_user_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + linkedUserId?: number | null + + @Column({ + name: 'linked_user_gradido_id', + type: 'varchar', + length: 36, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + linkedUserGradidoID: string | null + + @Column({ + name: 'linked_user_name', + type: 'varchar', + length: 512, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + linkedUserName: string | null + + @Column({ + name: 'linked_transaction_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + linkedTransactionId?: number | null + + @OneToOne(() => Contribution, (contribution) => contribution.transaction) + @JoinColumn({ name: 'id', referencedColumnName: 'transactionId' }) + contribution?: Contribution | null + + @OneToOne(() => Transaction) + @JoinColumn({ name: 'previous' }) + previousTransaction?: Transaction | null +} diff --git a/database/entity/Transaction.ts b/database/entity/Transaction.ts index 5365b0f70..4000e3c85 100644 --- a/database/entity/Transaction.ts +++ b/database/entity/Transaction.ts @@ -1 +1 @@ -export { Transaction } from './0036-unique_previous_in_transactions/Transaction' +export { Transaction } from './0066-x-community-sendcoins-transactions_table/Transaction' diff --git a/database/migrations/0066-x-community-sendcoins-transactions_table.ts b/database/migrations/0066-x-community-sendcoins-transactions_table.ts new file mode 100644 index 000000000..2a90f297a --- /dev/null +++ b/database/migrations/0066-x-community-sendcoins-transactions_table.ts @@ -0,0 +1,76 @@ +/* MIGRATION TO add users that have a transaction but do not exist */ + +/* 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` MODIFY COLUMN `previous` int(10) unsigned DEFAULT NULL NULL AFTER `id`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `type_id` int(10) DEFAULT NULL NULL AFTER `previous`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `transaction_link_id` int(10) unsigned DEFAULT NULL NULL AFTER `type_id`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `amount` decimal(40,20) DEFAULT NULL NULL AFTER `transaction_link_id`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `balance` decimal(40,20) DEFAULT NULL NULL AFTER `amount`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `balance_date` datetime(3) DEFAULT current_timestamp(3) NOT NULL AFTER `balance`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `decay` decimal(40,20) DEFAULT NULL NULL AFTER `balance_date`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `decay_start` datetime(3) DEFAULT NULL NULL AFTER `decay`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `memo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL AFTER `decay_start`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `creation_date` datetime(3) DEFAULT NULL NULL AFTER `memo`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `user_id` int(10) unsigned NOT NULL AFTER `creation_date`;', + ) + await queryFn( + 'ALTER TABLE `transactions` ADD COLUMN `user_gradido_id` char(36) DEFAULT NULL NULL AFTER `user_id`;', + ) + await queryFn( + 'ALTER TABLE `transactions` ADD COLUMN `user_name` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL NULL AFTER `user_gradido_id`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `linked_user_id` int(10) unsigned DEFAULT NULL NULL AFTER `user_name`;', + ) + await queryFn( + 'ALTER TABLE `transactions` ADD COLUMN `linked_user_gradido_id` char(36) DEFAULT NULL NULL AFTER `linked_user_id`;', + ) + await queryFn( + 'ALTER TABLE `transactions` ADD COLUMN `linked_user_name` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL NULL AFTER `linked_user_gradido_id`;', + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `linked_transaction_id` int(10) DEFAULT NULL NULL AFTER `linked_user_name`;', + ) + await queryFn( + `UPDATE transactions t, users u SET t.user_gradido_id = u.gradido_id, t.user_name = concat(u.first_name, ' ', u.last_name) WHERE t.user_id = u.id and t.user_gradido_id is null;`, + ) + await queryFn( + 'ALTER TABLE `transactions` MODIFY COLUMN `user_gradido_id` char(36) NOT NULL AFTER `user_id`;', + ) + await queryFn( + `UPDATE transactions t, users u SET t.linked_user_gradido_id = u.gradido_id, t.linked_user_name = concat(u.first_name, ' ', u.last_name) WHERE t.linked_user_id = u.id and t.linked_user_gradido_id is null;`, + ) +} + +/* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn('ALTER TABLE `transactions` DROP COLUMN `user_gradido_id`;') + await queryFn('ALTER TABLE `transactions` DROP COLUMN `user_name`;') + await queryFn('ALTER TABLE `transactions` DROP COLUMN `linked_user_gradido_id`;') + await queryFn('ALTER TABLE `transactions` DROP COLUMN `linked_user_name`;') +} diff --git a/dht-node/src/config/index.ts b/dht-node/src/config/index.ts index 5c4676337..eca5dbbb5 100644 --- a/dht-node/src/config/index.ts +++ b/dht-node/src/config/index.ts @@ -3,7 +3,7 @@ import dotenv from 'dotenv' dotenv.config() const constants = { - DB_VERSION: '0065-refactor_communities_table', + DB_VERSION: '0066-x-community-sendcoins-transactions_table', LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info LOG_LEVEL: process.env.LOG_LEVEL || 'info', diff --git a/federation/src/config/index.ts b/federation/src/config/index.ts index 70a155d63..66d8a056c 100644 --- a/federation/src/config/index.ts +++ b/federation/src/config/index.ts @@ -11,7 +11,7 @@ Decimal.set({ */ const constants = { - DB_VERSION: '0065-refactor_communities_table', + DB_VERSION: '0066-x-community-sendcoins-transactions_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