Merge remote-tracking branch 'origin/master' into 2800-feature-backend-read-communities-data-from-database

This commit is contained in:
Claus-Peter Hübner 2023-03-15 00:41:48 +01:00
commit 8e4d4cb9ab
32 changed files with 636 additions and 263 deletions

View File

@ -10,7 +10,7 @@ Decimal.set({
}) })
const constants = { const constants = {
DB_VERSION: '0060-update_communities_table', DB_VERSION: '0061-event_refactoring',
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
LOG4JS_CONFIG: 'log4js-config.json', LOG4JS_CONFIG: 'log4js-config.json',
// default log level on production should be info // default log level on production should be info

View File

@ -1,212 +1,217 @@
import { EventProtocol as DbEvent } from '@entity/EventProtocol' import { Event as DbEvent } from '@entity/Event'
import { User as DbUser } from '@entity/User'
import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage'
import { Contribution as DbContribution } from '@entity/Contribution'
import { Transaction as DbTransaction } from '@entity/Transaction'
import Decimal from 'decimal.js-light' import Decimal from 'decimal.js-light'
import { EventProtocolType } from './EventProtocolType' import { EventProtocolType } from './EventProtocolType'
export const Event = ( export const Event = (
type: EventProtocolType, type: EventProtocolType,
userId: number, affectedUser: DbUser,
xUserId: number | null = null, actingUser: DbUser,
xCommunityId: number | null = null, involvedUser: DbUser | null = null,
transactionId: number | null = null, involvedTransaction: DbTransaction | null = null,
contributionId: number | null = null, involvedContribution: DbContribution | null = null,
involvedContributionMessage: DbContributionMessage | null = null,
amount: Decimal | null = null, amount: Decimal | null = null,
messageId: number | null = null,
): DbEvent => { ): DbEvent => {
const event = new DbEvent() const event = new DbEvent()
event.type = type event.type = type
event.userId = userId event.affectedUser = affectedUser
event.xUserId = xUserId event.actingUser = actingUser
event.xCommunityId = xCommunityId event.involvedUser = involvedUser
event.transactionId = transactionId event.involvedTransaction = involvedTransaction
event.contributionId = contributionId event.involvedContribution = involvedContribution
event.involvedContributionMessage = involvedContributionMessage
event.amount = amount event.amount = amount
event.messageId = messageId
return event return event
} }
export const EVENT_CONTRIBUTION_CREATE = async ( export const EVENT_CONTRIBUTION_CREATE = async (
userId: number, user: DbUser,
contributionId: number, contribution: DbContribution,
amount: Decimal, amount: Decimal,
): Promise<DbEvent> => ): Promise<DbEvent> =>
Event( Event(
EventProtocolType.CONTRIBUTION_CREATE, EventProtocolType.CONTRIBUTION_CREATE,
userId, user,
user,
null, null,
null, null,
contribution,
null, null,
contributionId,
amount, amount,
).save() ).save()
export const EVENT_CONTRIBUTION_DELETE = async ( export const EVENT_CONTRIBUTION_DELETE = async (
userId: number, user: DbUser,
contributionId: number, contribution: DbContribution,
amount: Decimal, amount: Decimal,
): Promise<DbEvent> => ): Promise<DbEvent> =>
Event( Event(
EventProtocolType.CONTRIBUTION_DELETE, EventProtocolType.CONTRIBUTION_DELETE,
userId, user,
user,
null, null,
null, null,
contribution,
null, null,
contributionId,
amount, amount,
).save() ).save()
export const EVENT_CONTRIBUTION_UPDATE = async ( export const EVENT_CONTRIBUTION_UPDATE = async (
userId: number, user: DbUser,
contributionId: number, contribution: DbContribution,
amount: Decimal, amount: Decimal,
): Promise<DbEvent> => ): Promise<DbEvent> =>
Event( Event(
EventProtocolType.CONTRIBUTION_UPDATE, EventProtocolType.CONTRIBUTION_UPDATE,
userId, user,
user,
null, null,
null, null,
contribution,
null, null,
contributionId,
amount, amount,
).save() ).save()
export const EVENT_ADMIN_CONTRIBUTION_CREATE = async ( export const EVENT_ADMIN_CONTRIBUTION_CREATE = async (
userId: number, user: DbUser,
contributionId: number, moderator: DbUser,
contribution: DbContribution,
amount: Decimal, amount: Decimal,
): Promise<DbEvent> => ): Promise<DbEvent> =>
Event( Event(
EventProtocolType.ADMIN_CONTRIBUTION_CREATE, EventProtocolType.ADMIN_CONTRIBUTION_CREATE,
userId, user,
moderator,
null, null,
null, null,
contribution,
null, null,
contributionId,
amount, amount,
).save() ).save()
export const EVENT_ADMIN_CONTRIBUTION_UPDATE = async ( export const EVENT_ADMIN_CONTRIBUTION_UPDATE = async (
userId: number, user: DbUser,
contributionId: number, moderator: DbUser,
contribution: DbContribution,
amount: Decimal, amount: Decimal,
): Promise<DbEvent> => ): Promise<DbEvent> =>
Event( Event(
EventProtocolType.ADMIN_CONTRIBUTION_UPDATE, EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
userId, user,
moderator,
null, null,
null, null,
contribution,
null, null,
contributionId,
amount, amount,
).save() ).save()
export const EVENT_ADMIN_CONTRIBUTION_DELETE = async ( export const EVENT_ADMIN_CONTRIBUTION_DELETE = async (
userId: number, user: DbUser,
contributionId: number, moderator: DbUser,
contribution: DbContribution,
amount: Decimal, amount: Decimal,
): Promise<DbEvent> => ): Promise<DbEvent> =>
Event( Event(
EventProtocolType.ADMIN_CONTRIBUTION_DELETE, EventProtocolType.ADMIN_CONTRIBUTION_DELETE,
userId, user,
moderator,
null, null,
null, null,
contribution,
null, null,
contributionId,
amount, amount,
).save() ).save()
export const EVENT_CONTRIBUTION_CONFIRM = async ( export const EVENT_CONTRIBUTION_CONFIRM = async (
userId: number, user: DbUser,
contributionId: number, moderator: DbUser,
contribution: DbContribution,
amount: Decimal, amount: Decimal,
): Promise<DbEvent> => ): Promise<DbEvent> =>
Event( Event(
EventProtocolType.CONTRIBUTION_CONFIRM, EventProtocolType.CONTRIBUTION_CONFIRM,
userId, user,
moderator,
null, null,
null, null,
contribution,
null, null,
contributionId,
amount, amount,
).save() ).save()
export const EVENT_ADMIN_CONTRIBUTION_DENY = async ( export const EVENT_ADMIN_CONTRIBUTION_DENY = async (
userId: number, user: DbUser,
xUserId: number, moderator: DbUser,
contributionId: number, contribution: DbContribution,
amount: Decimal, amount: Decimal,
): Promise<DbEvent> => ): Promise<DbEvent> =>
Event( Event(
EventProtocolType.ADMIN_CONTRIBUTION_DENY, EventProtocolType.ADMIN_CONTRIBUTION_DENY,
userId, user,
xUserId, moderator,
null, null,
null, null,
contributionId, contribution,
null,
amount, amount,
).save() ).save()
export const EVENT_TRANSACTION_SEND = async ( export const EVENT_TRANSACTION_SEND = async (
userId: number, user: DbUser,
xUserId: number, involvedUser: DbUser,
transactionId: number, transaction: DbTransaction,
amount: Decimal, amount: Decimal,
): Promise<DbEvent> => ): Promise<DbEvent> =>
Event( Event(
EventProtocolType.TRANSACTION_SEND, EventProtocolType.TRANSACTION_SEND,
userId, user,
xUserId, user,
involvedUser,
transaction,
null, null,
transactionId,
null, null,
amount, amount,
).save() ).save()
export const EVENT_TRANSACTION_RECEIVE = async ( export const EVENT_TRANSACTION_RECEIVE = async (
userId: number, user: DbUser,
xUserId: number, involvedUser: DbUser,
transactionId: number, transaction: DbTransaction,
amount: Decimal, amount: Decimal,
): Promise<DbEvent> => ): Promise<DbEvent> =>
Event( Event(
EventProtocolType.TRANSACTION_RECEIVE, EventProtocolType.TRANSACTION_RECEIVE,
userId, user,
xUserId, involvedUser,
involvedUser,
transaction,
null, null,
transactionId,
null, null,
amount, amount,
).save() ).save()
export const EVENT_LOGIN = async (userId: number): Promise<DbEvent> => export const EVENT_LOGIN = async (user: DbUser): Promise<DbEvent> =>
Event(EventProtocolType.LOGIN, userId, null, null, null, null, null, null).save() Event(EventProtocolType.LOGIN, user, user).save()
export const EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = async ( export const EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = async (user: DbUser): Promise<DbEvent> =>
userId: number, Event(EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL, user, { id: 0 } as DbUser).save()
): Promise<DbEvent> => Event(EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL, userId).save()
export const EVENT_SEND_CONFIRMATION_EMAIL = async (userId: number): Promise<DbEvent> => export const EVENT_SEND_CONFIRMATION_EMAIL = async (user: DbUser): Promise<DbEvent> =>
Event(EventProtocolType.SEND_CONFIRMATION_EMAIL, userId).save() Event(EventProtocolType.SEND_CONFIRMATION_EMAIL, user, user).save()
export const EVENT_ADMIN_SEND_CONFIRMATION_EMAIL = async (userId: number): Promise<DbEvent> => export const EVENT_ADMIN_SEND_CONFIRMATION_EMAIL = async (
Event(EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL, userId).save() user: DbUser,
moderator: DbUser,
): Promise<DbEvent> =>
Event(EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL, user, moderator).save()
/* export const EVENT_REDEEM_REGISTER = async ( export const EVENT_REGISTER = async (user: DbUser): Promise<DbEvent> =>
userId: number, Event(EventProtocolType.REGISTER, user, user).save()
transactionId: number | null = null,
contributionId: number | null = null,
): Promise<Event> =>
Event(
EventProtocolType.REDEEM_REGISTER,
userId,
null,
null,
transactionId,
contributionId,
).save()
*/
export const EVENT_REGISTER = async (userId: number): Promise<DbEvent> => export const EVENT_ACTIVATE_ACCOUNT = async (user: DbUser): Promise<DbEvent> =>
Event(EventProtocolType.REGISTER, userId).save() Event(EventProtocolType.ACTIVATE_ACCOUNT, user, user).save()
export const EVENT_ACTIVATE_ACCOUNT = async (userId: number): Promise<DbEvent> =>
Event(EventProtocolType.ACTIVATE_ACCOUNT, userId).save()

View File

@ -21,9 +21,13 @@ export async function requestGetPublicKey(dbCom: DbCommunity): Promise<string |
} }
} }
` `
const variables = {}
try { try {
const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest(query) const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest(
query,
variables,
)
logger.debug(`Response-Data:`, data, errors, extensions, headers, status) logger.debug(`Response-Data:`, data, errors, extensions, headers, status)
if (data) { if (data) {
logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey) logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey)

View File

@ -21,9 +21,13 @@ export async function requestGetPublicKey(dbCom: DbCommunity): Promise<string |
} }
} }
` `
const variables = {}
try { try {
const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest(query) const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest(
query,
variables,
)
logger.debug(`Response-Data:`, data, errors, extensions, headers, status) logger.debug(`Response-Data:`, data, errors, extensions, headers, status)
if (data) { if (data) {
logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey) logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey)

View File

@ -1,8 +1,14 @@
import { GraphQLClient } from 'graphql-request' import { GraphQLClient } from 'graphql-request'
import { PatchedRequestInit } from 'graphql-request/dist/types' import { PatchedRequestInit } from 'graphql-request/dist/types'
type ClientInstance = {
url: string
// eslint-disable-next-line no-use-before-define
client: GraphQLGetClient
}
export class GraphQLGetClient extends GraphQLClient { export class GraphQLGetClient extends GraphQLClient {
private static instance: GraphQLGetClient private static instanceArray: ClientInstance[] = []
/** /**
* The Singleton's constructor should always be private to prevent direct * The Singleton's constructor should always be private to prevent direct
@ -20,16 +26,18 @@ export class GraphQLGetClient extends GraphQLClient {
* just one instance of each subclass around. * just one instance of each subclass around.
*/ */
public static getInstance(url: string): GraphQLGetClient { public static getInstance(url: string): GraphQLGetClient {
if (!GraphQLGetClient.instance) { const instance = GraphQLGetClient.instanceArray.find((instance) => instance.url === url)
GraphQLGetClient.instance = new GraphQLGetClient(url, { if (instance) {
method: 'GET', return instance.client
jsonSerializer: {
parse: JSON.parse,
stringify: JSON.stringify,
},
})
} }
const client = new GraphQLGetClient(url, {
return GraphQLGetClient.instance method: 'GET',
jsonSerializer: {
parse: JSON.parse,
stringify: JSON.stringify,
},
})
GraphQLGetClient.instanceArray.push({ url, client } as ClientInstance)
return client
} }
} }

View File

@ -42,17 +42,18 @@ export async function validateCommunities(): Promise<void> {
pubKey, pubKey,
`${dbCom.endPoint}/${dbCom.apiVersion}`, `${dbCom.endPoint}/${dbCom.apiVersion}`,
) )
if (pubKey && pubKey === dbCom.publicKey.toString('hex')) { if (pubKey && pubKey === dbCom.publicKey.toString()) {
logger.info(`Federation: matching publicKey: ${pubKey}`) logger.info(`Federation: matching publicKey: ${pubKey}`)
await DbCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() }) await DbCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() })
logger.debug(`Federation: updated dbCom: ${JSON.stringify(dbCom)}`) logger.debug(`Federation: updated dbCom: ${JSON.stringify(dbCom)}`)
} else {
logger.warn(
`Federation: received not matching publicKey -> received: ${
pubKey || 'null'
}, expected: ${dbCom.publicKey.toString()} `,
)
// DbCommunity.delete({ id: dbCom.id })
} }
/*
else {
logger.warn(`Federation: received unknown publicKey -> delete dbCom with id=${dbCom.id} `)
DbCommunity.delete({ id: dbCom.id })
}
*/
} catch (err) { } catch (err) {
if (!isLogError(err)) { if (!isLogError(err)) {
logger.error(`Error:`, err) logger.error(`Error:`, err)

View File

@ -46,7 +46,7 @@ import { userFactory } from '@/seeds/factory/user'
import { creationFactory } from '@/seeds/factory/creation' import { creationFactory } from '@/seeds/factory/creation'
import { creations } from '@/seeds/creation/index' import { creations } from '@/seeds/creation/index'
import { peterLustig } from '@/seeds/users/peter-lustig' import { peterLustig } from '@/seeds/users/peter-lustig'
import { EventProtocol } from '@entity/EventProtocol' import { Event as DbEvent } from '@entity/Event'
import { Contribution } from '@entity/Contribution' import { Contribution } from '@entity/Contribution'
import { Transaction as DbTransaction } from '@entity/Transaction' import { Transaction as DbTransaction } from '@entity/Transaction'
import { User } from '@entity/User' import { User } from '@entity/User'
@ -279,12 +279,13 @@ describe('ContributionResolver', () => {
}) })
it('stores the CONTRIBUTION_CREATE event in the database', async () => { it('stores the CONTRIBUTION_CREATE event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.CONTRIBUTION_CREATE, type: EventProtocolType.CONTRIBUTION_CREATE,
affectedUserId: bibi.id,
actingUserId: bibi.id,
involvedContributionId: pendingContribution.data.createContribution.id,
amount: expect.decimalEqual(100), amount: expect.decimalEqual(100),
contributionId: pendingContribution.data.createContribution.id,
userId: bibi.id,
}), }),
) )
}) })
@ -584,12 +585,13 @@ describe('ContributionResolver', () => {
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.CONTRIBUTION_UPDATE, type: EventProtocolType.CONTRIBUTION_UPDATE,
affectedUserId: bibi.id,
actingUserId: bibi.id,
involvedContributionId: pendingContribution.data.createContribution.id,
amount: expect.decimalEqual(10), amount: expect.decimalEqual(10),
contributionId: pendingContribution.data.createContribution.id,
userId: bibi.id,
}), }),
) )
}) })
@ -814,12 +816,12 @@ describe('ContributionResolver', () => {
}) })
it('stores the ADMIN_CONTRIBUTION_DENY event in the database', async () => { it('stores the ADMIN_CONTRIBUTION_DENY event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ADMIN_CONTRIBUTION_DENY, type: EventProtocolType.ADMIN_CONTRIBUTION_DENY,
userId: bibi.id, affectedUserId: bibi.id,
xUserId: admin.id, actingUserId: admin.id,
contributionId: contributionToDeny.data.createContribution.id, involvedContributionId: contributionToDeny.data.createContribution.id,
amount: expect.decimalEqual(100), amount: expect.decimalEqual(100),
}), }),
) )
@ -942,12 +944,13 @@ describe('ContributionResolver', () => {
}) })
it('stores the CONTRIBUTION_DELETE event in the database', async () => { it('stores the CONTRIBUTION_DELETE event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.CONTRIBUTION_DELETE, type: EventProtocolType.CONTRIBUTION_DELETE,
contributionId: contributionToDelete.data.createContribution.id, affectedUserId: bibi.id,
actingUserId: bibi.id,
involvedContributionId: contributionToDelete.data.createContribution.id,
amount: expect.decimalEqual(100), amount: expect.decimalEqual(100),
userId: bibi.id,
}), }),
) )
}) })
@ -2031,10 +2034,11 @@ describe('ContributionResolver', () => {
}) })
it('stores the ADMIN_CONTRIBUTION_CREATE event in the database', async () => { it('stores the ADMIN_CONTRIBUTION_CREATE event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ADMIN_CONTRIBUTION_CREATE, type: EventProtocolType.ADMIN_CONTRIBUTION_CREATE,
userId: admin.id, affectedUserId: bibi.id,
actingUserId: admin.id,
amount: expect.decimalEqual(200), amount: expect.decimalEqual(200),
}), }),
) )
@ -2232,7 +2236,7 @@ describe('ContributionResolver', () => {
mutate({ mutate({
mutation: adminUpdateContribution, mutation: adminUpdateContribution,
variables: { variables: {
id: creation ? creation.id : -1, id: creation?.id,
email: 'peter@lustig.de', email: 'peter@lustig.de',
amount: new Decimal(300), amount: new Decimal(300),
memo: 'Danke Peter!', memo: 'Danke Peter!',
@ -2256,10 +2260,11 @@ describe('ContributionResolver', () => {
}) })
it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => { it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE, type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
userId: admin.id, affectedUserId: creation?.userId,
actingUserId: admin.id,
amount: 300, amount: 300,
}), }),
) )
@ -2273,7 +2278,7 @@ describe('ContributionResolver', () => {
mutate({ mutate({
mutation: adminUpdateContribution, mutation: adminUpdateContribution,
variables: { variables: {
id: creation ? creation.id : -1, id: creation?.id,
email: 'peter@lustig.de', email: 'peter@lustig.de',
amount: new Decimal(200), amount: new Decimal(200),
memo: 'Das war leider zu Viel!', memo: 'Das war leider zu Viel!',
@ -2297,10 +2302,11 @@ describe('ContributionResolver', () => {
}) })
it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => { it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE, type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
userId: admin.id, affectedUserId: creation?.userId,
actingUserId: admin.id,
amount: expect.decimalEqual(200), amount: expect.decimalEqual(200),
}), }),
) )
@ -2371,7 +2377,7 @@ describe('ContributionResolver', () => {
mutate({ mutate({
mutation: adminDeleteContribution, mutation: adminDeleteContribution,
variables: { variables: {
id: creation ? creation.id : -1, id: creation?.id,
}, },
}), }),
).resolves.toEqual( ).resolves.toEqual(
@ -2382,10 +2388,12 @@ describe('ContributionResolver', () => {
}) })
it('stores the ADMIN_CONTRIBUTION_DELETE event in the database', async () => { it('stores the ADMIN_CONTRIBUTION_DELETE event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ADMIN_CONTRIBUTION_DELETE, type: EventProtocolType.ADMIN_CONTRIBUTION_DELETE,
userId: admin.id, affectedUserId: creation?.userId,
actingUserId: admin.id,
involvedContributionId: creation?.id,
amount: expect.decimalEqual(200), amount: expect.decimalEqual(200),
}), }),
) )
@ -2538,7 +2546,7 @@ describe('ContributionResolver', () => {
}) })
it('stores the CONTRIBUTION_CONFIRM event in the database', async () => { it('stores the CONTRIBUTION_CONFIRM event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.CONTRIBUTION_CONFIRM, type: EventProtocolType.CONTRIBUTION_CONFIRM,
}), }),
@ -2570,7 +2578,7 @@ describe('ContributionResolver', () => {
}) })
it('stores the SEND_CONFIRMATION_EMAIL event in the database', async () => { it('stores the SEND_CONFIRMATION_EMAIL event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.SEND_CONFIRMATION_EMAIL, type: EventProtocolType.SEND_CONFIRMATION_EMAIL,
}), }),

View File

@ -91,7 +91,7 @@ export class ContributionResolver {
logger.trace('contribution to save', contribution) logger.trace('contribution to save', contribution)
await DbContribution.save(contribution) await DbContribution.save(contribution)
await EVENT_CONTRIBUTION_CREATE(user.id, contribution.id, amount) await EVENT_CONTRIBUTION_CREATE(user, contribution, amount)
return new UnconfirmedContribution(contribution, user, creations) return new UnconfirmedContribution(contribution, user, creations)
} }
@ -119,7 +119,7 @@ export class ContributionResolver {
contribution.deletedAt = new Date() contribution.deletedAt = new Date()
await contribution.save() await contribution.save()
await EVENT_CONTRIBUTION_DELETE(user.id, contribution.id, contribution.amount) await EVENT_CONTRIBUTION_DELETE(user, contribution, contribution.amount)
const res = await contribution.softRemove() const res = await contribution.softRemove()
return !!res return !!res
@ -249,7 +249,7 @@ export class ContributionResolver {
contributionToUpdate.updatedAt = new Date() contributionToUpdate.updatedAt = new Date()
await DbContribution.save(contributionToUpdate) await DbContribution.save(contributionToUpdate)
await EVENT_CONTRIBUTION_UPDATE(user.id, contributionId, amount) await EVENT_CONTRIBUTION_UPDATE(user, contributionToUpdate, amount)
return new UnconfirmedContribution(contributionToUpdate, user, creations) return new UnconfirmedContribution(contributionToUpdate, user, creations)
} }
@ -306,7 +306,7 @@ export class ContributionResolver {
await DbContribution.save(contribution) await DbContribution.save(contribution)
await EVENT_ADMIN_CONTRIBUTION_CREATE(moderator.id, contribution.id, amount) await EVENT_ADMIN_CONTRIBUTION_CREATE(emailContact.user, moderator, contribution, amount)
return getUserCreation(emailContact.userId, clientTimezoneOffset) return getUserCreation(emailContact.userId, clientTimezoneOffset)
} }
@ -374,7 +374,12 @@ export class ContributionResolver {
result.creation = await getUserCreation(emailContact.user.id, clientTimezoneOffset) result.creation = await getUserCreation(emailContact.user.id, clientTimezoneOffset)
await EVENT_ADMIN_CONTRIBUTION_UPDATE(emailContact.user.id, contributionToUpdate.id, amount) await EVENT_ADMIN_CONTRIBUTION_UPDATE(
emailContact.user,
moderator,
contributionToUpdate,
amount,
)
return result return result
} }
@ -432,7 +437,12 @@ export class ContributionResolver {
await contribution.save() await contribution.save()
const res = await contribution.softRemove() const res = await contribution.softRemove()
await EVENT_ADMIN_CONTRIBUTION_DELETE(contribution.userId, contribution.id, contribution.amount) await EVENT_ADMIN_CONTRIBUTION_DELETE(
{ id: contribution.userId } as DbUser,
moderator,
contribution,
contribution.amount,
)
void sendContributionDeletedEmail({ void sendContributionDeletedEmail({
firstName: user.firstName, firstName: user.firstName,
@ -545,7 +555,7 @@ export class ContributionResolver {
await queryRunner.release() await queryRunner.release()
} }
await EVENT_CONTRIBUTION_CONFIRM(user.id, contribution.id, contribution.amount) await EVENT_CONTRIBUTION_CONFIRM(user, moderatorUser, contribution, contribution.amount)
} finally { } finally {
releaseLock() releaseLock()
} }
@ -632,9 +642,9 @@ export class ContributionResolver {
const res = await contributionToUpdate.save() const res = await contributionToUpdate.save()
await EVENT_ADMIN_CONTRIBUTION_DENY( await EVENT_ADMIN_CONTRIBUTION_DENY(
contributionToUpdate.userId, user,
moderator.id, moderator,
contributionToUpdate.id, contributionToUpdate,
contributionToUpdate.amount, contributionToUpdate.amount,
) )

View File

@ -18,7 +18,7 @@ import { bobBaumeister } from '@/seeds/users/bob-baumeister'
import { garrickOllivander } from '@/seeds/users/garrick-ollivander' import { garrickOllivander } from '@/seeds/users/garrick-ollivander'
import { peterLustig } from '@/seeds/users/peter-lustig' import { peterLustig } from '@/seeds/users/peter-lustig'
import { stephenHawking } from '@/seeds/users/stephen-hawking' import { stephenHawking } from '@/seeds/users/stephen-hawking'
import { EventProtocol } from '@entity/EventProtocol' import { Event as DbEvent } from '@entity/Event'
import { Transaction } from '@entity/Transaction' import { Transaction } from '@entity/Transaction'
import { User } from '@entity/User' import { User } from '@entity/User'
import { cleanDB, testEnvironment } from '@test/helpers' import { cleanDB, testEnvironment } from '@test/helpers'
@ -341,12 +341,13 @@ describe('send coins', () => {
memo: 'unrepeatable memo', memo: 'unrepeatable memo',
}) })
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.TRANSACTION_SEND, type: EventProtocolType.TRANSACTION_SEND,
userId: user[1].id, affectedUserId: user[1].id,
transactionId: transaction[0].id, actingUserId: user[1].id,
xUserId: user[0].id, involvedUserId: user[0].id,
involvedTransactionId: transaction[0].id,
}), }),
) )
}) })
@ -358,12 +359,13 @@ describe('send coins', () => {
memo: 'unrepeatable memo', memo: 'unrepeatable memo',
}) })
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.TRANSACTION_RECEIVE, type: EventProtocolType.TRANSACTION_RECEIVE,
userId: user[0].id, affectedUserId: user[0].id,
transactionId: transaction[0].id, actingUserId: user[1].id,
xUserId: user[1].id, involvedUserId: user[1].id,
involvedTransactionId: transaction[0].id,
}), }),
) )
}) })

View File

@ -138,17 +138,12 @@ export const executeTransaction = async (
await queryRunner.commitTransaction() await queryRunner.commitTransaction()
logger.info(`commit Transaction successful...`) logger.info(`commit Transaction successful...`)
await EVENT_TRANSACTION_SEND( await EVENT_TRANSACTION_SEND(sender, recipient, transactionSend, transactionSend.amount)
transactionSend.userId,
transactionSend.linkedUserId,
transactionSend.id,
transactionSend.amount.mul(-1),
)
await EVENT_TRANSACTION_RECEIVE( await EVENT_TRANSACTION_RECEIVE(
transactionReceive.userId, recipient,
transactionReceive.linkedUserId, sender,
transactionReceive.id, transactionReceive,
transactionReceive.amount, transactionReceive.amount,
) )
} catch (e) { } catch (e) {

View File

@ -40,7 +40,7 @@ import { transactionLinkFactory } from '@/seeds/factory/transactionLink'
import { ContributionLink } from '@model/ContributionLink' import { ContributionLink } from '@model/ContributionLink'
import { TransactionLink } from '@entity/TransactionLink' import { TransactionLink } from '@entity/TransactionLink'
import { EventProtocolType } from '@/event/EventProtocolType' import { EventProtocolType } from '@/event/EventProtocolType'
import { EventProtocol } from '@entity/EventProtocol' import { Event as DbEvent } from '@entity/Event'
import { validate as validateUUID, version as versionUUID } from 'uuid' import { validate as validateUUID, version as versionUUID } from 'uuid'
import { peterLustig } from '@/seeds/users/peter-lustig' import { peterLustig } from '@/seeds/users/peter-lustig'
import { UserContact } from '@entity/UserContact' import { UserContact } from '@entity/UserContact'
@ -187,10 +187,11 @@ describe('UserResolver', () => {
{ email: 'peter@lustig.de' }, { email: 'peter@lustig.de' },
{ relations: ['user'] }, { relations: ['user'] },
) )
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.REGISTER, type: EventProtocolType.REGISTER,
userId: userConatct.user.id, affectedUserId: userConatct.user.id,
actingUserId: userConatct.user.id,
}), }),
) )
}) })
@ -216,10 +217,11 @@ describe('UserResolver', () => {
}) })
it('stores the SEND_CONFIRMATION_EMAIL event in the database', async () => { it('stores the SEND_CONFIRMATION_EMAIL event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.SEND_CONFIRMATION_EMAIL, type: EventProtocolType.SEND_CONFIRMATION_EMAIL,
userId: user[0].id, affectedUserId: user[0].id,
actingUserId: user[0].id,
}), }),
) )
}) })
@ -261,10 +263,11 @@ describe('UserResolver', () => {
{ email: 'peter@lustig.de' }, { email: 'peter@lustig.de' },
{ relations: ['user'] }, { relations: ['user'] },
) )
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL, type: EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL,
userId: userConatct.user.id, affectedUserId: userConatct.user.id,
actingUserId: 0,
}), }),
) )
}) })
@ -361,20 +364,22 @@ describe('UserResolver', () => {
}) })
it('stores the ACTIVATE_ACCOUNT event in the database', async () => { it('stores the ACTIVATE_ACCOUNT event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ACTIVATE_ACCOUNT, type: EventProtocolType.ACTIVATE_ACCOUNT,
userId: user[0].id, affectedUserId: user[0].id,
actingUserId: user[0].id,
}), }),
) )
}) })
it('stores the REDEEM_REGISTER event in the database', async () => { it('stores the REDEEM_REGISTER event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.REDEEM_REGISTER, type: EventProtocolType.REDEEM_REGISTER,
userId: result.data.createUser.id, affectedUserId: result.data.createUser.id,
contributionId: link.id, actingUserId: result.data.createUser.id,
involvedContributionId: link.id,
}), }),
) )
}) })
@ -454,10 +459,12 @@ describe('UserResolver', () => {
}) })
it('stores the REDEEM_REGISTER event in the database', async () => { it('stores the REDEEM_REGISTER event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.REDEEM_REGISTER, type: EventProtocolType.REDEEM_REGISTER,
userId: newUser.data.createUser.id, affectedUserId: newUser.data.createUser.id,
actingUserId: newUser.data.createUser.id,
involvedTransactionId: transactionLink.id,
}), }),
) )
}) })
@ -685,10 +692,11 @@ describe('UserResolver', () => {
{ email: 'bibi@bloxberg.de' }, { email: 'bibi@bloxberg.de' },
{ relations: ['user'] }, { relations: ['user'] },
) )
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.LOGIN, type: EventProtocolType.LOGIN,
userId: userConatct.user.id, affectedUserId: userConatct.user.id,
actingUserId: userConatct.user.id,
}), }),
) )
}) })
@ -933,10 +941,11 @@ describe('UserResolver', () => {
}) })
it('stores the LOGIN event in the database', async () => { it('stores the LOGIN event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.LOGIN, type: EventProtocolType.LOGIN,
userId: user[0].id, affectedUserId: user[0].id,
actingUserId: user[0].id,
}), }),
) )
}) })
@ -1852,10 +1861,11 @@ describe('UserResolver', () => {
{ email: 'bibi@bloxberg.de' }, { email: 'bibi@bloxberg.de' },
{ relations: ['user'] }, { relations: ['user'] },
) )
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL, type: EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL,
userId: userConatct.user.id, affectedUserId: userConatct.user.id,
actingUserId: admin.id,
}), }),
) )
}) })

View File

@ -20,7 +20,9 @@ import { getConnection, getCustomRepository, IsNull, Not } from '@dbTools/typeor
import { User as DbUser } from '@entity/User' import { User as DbUser } from '@entity/User'
import { UserContact as DbUserContact } from '@entity/UserContact' import { UserContact as DbUserContact } from '@entity/UserContact'
import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink'
import { Transaction as DbTransaction } from '@entity/Transaction'
import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink'
import { Contribution as DbContribution } from '@entity/Contribution'
import { UserRepository } from '@repository/User' import { UserRepository } from '@repository/User'
import { User } from '@model/User' import { User } from '@model/User'
@ -182,7 +184,7 @@ export class UserResolver {
value: encode(dbUser.gradidoID), value: encode(dbUser.gradidoID),
}) })
await EVENT_LOGIN(user.id) await EVENT_LOGIN(dbUser)
logger.info(`successful Login: ${JSON.stringify(user, null, 2)}`) logger.info(`successful Login: ${JSON.stringify(user, null, 2)}`)
return user return user
} }
@ -252,7 +254,7 @@ export class UserResolver {
language: foundUser.language, // use language of the emails owner for sending language: foundUser.language, // use language of the emails owner for sending
}) })
await EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL(foundUser.id) await EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL(foundUser)
logger.info( logger.info(
`sendAccountMultiRegistrationEmail by ${firstName} ${lastName} to ${foundUser.firstName} ${foundUser.lastName} <${email}>`, `sendAccountMultiRegistrationEmail by ${firstName} ${lastName} to ${foundUser.firstName} ${foundUser.lastName} <${email}>`,
@ -270,7 +272,11 @@ export class UserResolver {
const gradidoID = await newGradidoID() const gradidoID = await newGradidoID()
const eventRegisterRedeem = Event(EventProtocolType.REDEEM_REGISTER, 0) const eventRegisterRedeem = Event(
EventProtocolType.REDEEM_REGISTER,
{ id: 0 } as DbUser,
{ id: 0 } as DbUser,
)
let dbUser = new DbUser() let dbUser = new DbUser()
dbUser.gradidoID = gradidoID dbUser.gradidoID = gradidoID
dbUser.firstName = firstName dbUser.firstName = firstName
@ -287,14 +293,16 @@ export class UserResolver {
logger.info('redeemCode found contributionLink', contributionLink) logger.info('redeemCode found contributionLink', contributionLink)
if (contributionLink) { if (contributionLink) {
dbUser.contributionLinkId = contributionLink.id dbUser.contributionLinkId = contributionLink.id
eventRegisterRedeem.contributionId = contributionLink.id // TODO this is so wrong
eventRegisterRedeem.involvedContribution = { id: contributionLink.id } as DbContribution
} }
} else { } else {
const transactionLink = await DbTransactionLink.findOne({ code: redeemCode }) const transactionLink = await DbTransactionLink.findOne({ code: redeemCode })
logger.info('redeemCode found transactionLink', transactionLink) logger.info('redeemCode found transactionLink', transactionLink)
if (transactionLink) { if (transactionLink) {
dbUser.referrerId = transactionLink.userId dbUser.referrerId = transactionLink.userId
eventRegisterRedeem.transactionId = transactionLink.id // TODO this is so wrong
eventRegisterRedeem.involvedTransaction = { id: transactionLink.id } as DbTransaction
} }
} }
} }
@ -333,7 +341,7 @@ export class UserResolver {
}) })
logger.info(`sendAccountActivationEmail of ${firstName}.${lastName} to ${email}`) logger.info(`sendAccountActivationEmail of ${firstName}.${lastName} to ${email}`)
await EVENT_SEND_CONFIRMATION_EMAIL(dbUser.id) await EVENT_SEND_CONFIRMATION_EMAIL(dbUser)
if (!emailSent) { if (!emailSent) {
logger.debug(`Account confirmation link: ${activationLink}`) logger.debug(`Account confirmation link: ${activationLink}`)
@ -350,10 +358,11 @@ export class UserResolver {
logger.info('createUser() successful...') logger.info('createUser() successful...')
if (redeemCode) { if (redeemCode) {
eventRegisterRedeem.userId = dbUser.id eventRegisterRedeem.affectedUser = dbUser
eventRegisterRedeem.actingUser = dbUser
await eventRegisterRedeem.save() await eventRegisterRedeem.save()
} else { } else {
await EVENT_REGISTER(dbUser.id) await EVENT_REGISTER(dbUser)
} }
return new User(dbUser) return new User(dbUser)
@ -469,7 +478,7 @@ export class UserResolver {
await queryRunner.commitTransaction() await queryRunner.commitTransaction()
logger.info('User and UserContact data written successfully...') logger.info('User and UserContact data written successfully...')
await EVENT_ACTIVATE_ACCOUNT(user.id) await EVENT_ACTIVATE_ACCOUNT(user)
} catch (e) { } catch (e) {
await queryRunner.rollbackTransaction() await queryRunner.rollbackTransaction()
throw new LogError('Error on writing User and User Contact data', e) throw new LogError('Error on writing User and User Contact data', e)
@ -779,9 +788,13 @@ export class UserResolver {
return null return null
} }
// TODO this is an admin function - needs refactor
@Authorized([RIGHTS.SEND_ACTIVATION_EMAIL]) @Authorized([RIGHTS.SEND_ACTIVATION_EMAIL])
@Mutation(() => Boolean) @Mutation(() => Boolean)
async sendActivationEmail(@Arg('email') email: string): Promise<boolean> { async sendActivationEmail(
@Arg('email') email: string,
@Ctx() context: Context,
): Promise<boolean> {
email = email.trim().toLowerCase() email = email.trim().toLowerCase()
// const user = await dbUser.findOne({ id: emailContact.userId }) // const user = await dbUser.findOne({ id: emailContact.userId })
const user = await findUserByEmail(email) const user = await findUserByEmail(email)
@ -806,7 +819,7 @@ export class UserResolver {
if (!emailSent) { if (!emailSent) {
logger.info(`Account confirmation link: ${activationLink}`) logger.info(`Account confirmation link: ${activationLink}`)
} else { } else {
await EVENT_ADMIN_SEND_CONFIRMATION_EMAIL(user.id) await EVENT_ADMIN_SEND_CONFIRMATION_EMAIL(user, getUser(context))
} }
return true return true

View File

@ -0,0 +1,83 @@
import { Contribution } from '../Contribution'
import { ContributionMessage } from '../ContributionMessage'
import { User } from '../User'
import { Transaction } from '../Transaction'
import Decimal from 'decimal.js-light'
import {
BaseEntity,
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
ManyToOne,
JoinColumn,
} from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
@Entity('events')
export class Event extends BaseEntity {
@PrimaryGeneratedColumn('increment', { unsigned: true })
id: number
@Column({ length: 100, nullable: false, collation: 'utf8mb4_unicode_ci' })
type: string
@CreateDateColumn({
name: 'created_at',
type: 'datetime',
default: () => 'CURRENT_TIMESTAMP(3)',
nullable: false,
})
createdAt: Date
@Column({ name: 'affected_user_id', unsigned: true, nullable: false })
affectedUserId: number
@ManyToOne(() => User)
@JoinColumn({ name: 'affected_user_id', referencedColumnName: 'id' })
affectedUser: User
@Column({ name: 'acting_user_id', unsigned: true, nullable: false })
actingUserId: number
@ManyToOne(() => User)
@JoinColumn({ name: 'acting_user_id', referencedColumnName: 'id' })
actingUser: User
@Column({ name: 'involved_user_id', type: 'int', unsigned: true, nullable: true })
involvedUserId: number | null
@ManyToOne(() => User)
@JoinColumn({ name: 'involved_user_id', referencedColumnName: 'id' })
involvedUser: User | null
@Column({ name: 'involved_transaction_id', type: 'int', unsigned: true, nullable: true })
involvedTransactionId: number | null
@ManyToOne(() => Transaction)
@JoinColumn({ name: 'involved_transaction_id', referencedColumnName: 'id' })
involvedTransaction: Transaction | null
@Column({ name: 'involved_contribution_id', type: 'int', unsigned: true, nullable: true })
involvedContributionId: number | null
@ManyToOne(() => Contribution)
@JoinColumn({ name: 'involved_contribution_id', referencedColumnName: 'id' })
involvedContribution: Contribution | null
@Column({ name: 'involved_contribution_message_id', type: 'int', unsigned: true, nullable: true })
involvedContributionMessageId: number | null
@ManyToOne(() => ContributionMessage)
@JoinColumn({ name: 'involved_contribution_message_id', referencedColumnName: 'id' })
involvedContributionMessage: ContributionMessage | null
@Column({
type: 'decimal',
precision: 40,
scale: 20,
nullable: true,
transformer: DecimalTransformer,
})
amount: Decimal | null
}

1
database/entity/Event.ts Normal file
View File

@ -0,0 +1 @@
export { Event } from './0061-event_refactoring/Event'

View File

@ -1 +0,0 @@
export { EventProtocol } from './0050-add_messageId_to_event_protocol/EventProtocol'

View File

@ -7,21 +7,21 @@ import { TransactionLink } from './TransactionLink'
import { User } from './User' import { User } from './User'
import { UserContact } from './UserContact' import { UserContact } from './UserContact'
import { Contribution } from './Contribution' import { Contribution } from './Contribution'
import { EventProtocol } from './EventProtocol' import { Event } from './Event'
import { ContributionMessage } from './ContributionMessage' import { ContributionMessage } from './ContributionMessage'
import { Community } from './Community' import { Community } from './Community'
export const entities = [ export const entities = [
Community,
Contribution, Contribution,
ContributionLink, ContributionLink,
ContributionMessage,
Event,
LoginElopageBuys, LoginElopageBuys,
LoginEmailOptIn, LoginEmailOptIn,
Migration, Migration,
Transaction, Transaction,
TransactionLink, TransactionLink,
User, User,
EventProtocol,
ContributionMessage,
UserContact, UserContact,
Community,
] ]

View File

@ -0,0 +1,98 @@
/* MIGRATION TO REFACTOR THE EVENT_PROTOCOL TABLE
*
* This migration refactors the `event_protocol` table.
* It renames the table to `event`, introduces new fields and renames others.
*/
/* 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<Array<any>>) {
await queryFn('RENAME TABLE `event_protocol` TO `events`;')
await queryFn('ALTER TABLE `events` RENAME COLUMN `user_id` TO `affected_user_id`;')
await queryFn(
'ALTER TABLE `events` ADD COLUMN `acting_user_id` int(10) unsigned DEFAULT NULL AFTER `affected_user_id`;',
)
await queryFn('UPDATE `events` SET `acting_user_id` = `affected_user_id`;')
await queryFn(
'ALTER TABLE `events` MODIFY COLUMN `acting_user_id` int(10) unsigned NOT NULL AFTER `affected_user_id`;',
)
await queryFn('ALTER TABLE `events` RENAME COLUMN `x_user_id` TO `involved_user_id`;')
await queryFn('ALTER TABLE `events` DROP COLUMN `x_community_id`;')
await queryFn('ALTER TABLE `events` RENAME COLUMN `transaction_id` TO `involved_transaction_id`;')
await queryFn(
'ALTER TABLE `events` RENAME COLUMN `contribution_id` TO `involved_contribution_id`;',
)
await queryFn(
'ALTER TABLE `events` MODIFY COLUMN `message_id` int(10) unsigned DEFAULT NULL AFTER `involved_contribution_id`;',
)
await queryFn(
'ALTER TABLE `events` RENAME COLUMN `message_id` TO `involved_contribution_message_id`;',
)
// Moderator id was saved in former user_id
await queryFn(
'UPDATE `events` LEFT JOIN `contributions` ON events.involved_contribution_id = contributions.id SET affected_user_id=contributions.user_id WHERE `type` = "ADMIN_CONTRIBUTION_CREATE";',
)
// inconsistent data on this type, since not all data can be reconstructed
await queryFn(
'UPDATE `events` LEFT JOIN `contributions` ON events.involved_contribution_id = contributions.id SET acting_user_id=0 WHERE `type` = "ADMIN_CONTRIBUTION_UPDATE";',
)
await queryFn(
'UPDATE `events` LEFT JOIN `contributions` ON events.involved_contribution_id = contributions.id SET acting_user_id=contributions.deleted_by WHERE `type` = "ADMIN_CONTRIBUTION_DELETE";',
)
await queryFn(
'UPDATE `events` LEFT JOIN `contributions` ON events.involved_contribution_id = contributions.id SET acting_user_id=contributions.confirmed_by WHERE `type` = "CONTRIBUTION_CONFIRM";',
)
await queryFn(
'UPDATE `events` LEFT JOIN `contributions` ON events.involved_contribution_id = contributions.id SET involved_user_id=NULL, acting_user_id=contributions.denied_by WHERE `type` = "ADMIN_CONTRIBUTION_DENY";',
)
await queryFn(
'UPDATE `events` SET acting_user_id=involved_user_id WHERE `type` = "TRANSACTION_RECEIVE";',
)
await queryFn('UPDATE `events` SET amount = amount * -1 WHERE `type` = "TRANSACTION_SEND";')
await queryFn(
'ALTER TABLE `events` MODIFY COLUMN `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3);',
)
}
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
await queryFn(
'ALTER TABLE `events` MODIFY COLUMN `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP();',
)
await queryFn('UPDATE `events` SET amount = amount * -1 WHERE `type` = "TRANSACTION_SEND";')
await queryFn(
'UPDATE `events` SET involved_user_id=acting_user_id WHERE `type` = "ADMIN_CONTRIBUTION_DENY";',
)
await queryFn(
'UPDATE `events` SET affected_user_id=acting_user_id WHERE `type` = "ADMIN_CONTRIBUTION_CREATE";',
)
await queryFn(
'ALTER TABLE `events` RENAME COLUMN `involved_contribution_message_id` TO `message_id`;',
)
await queryFn(
'ALTER TABLE `events` MODIFY COLUMN `message_id` int(10) unsigned DEFAULT NULL AFTER `amount`;',
)
await queryFn(
'ALTER TABLE `events` RENAME COLUMN `involved_contribution_id` TO `contribution_id`;',
)
await queryFn('ALTER TABLE `events` RENAME COLUMN `involved_transaction_id` TO `transaction_id`;')
await queryFn(
'ALTER TABLE `events` ADD COLUMN `x_community_id` int(10) unsigned DEFAULT NULL AFTER `involved_user_id`;',
)
await queryFn('ALTER TABLE `events` RENAME COLUMN `involved_user_id` TO `x_user_id`;')
await queryFn('ALTER TABLE `events` DROP COLUMN `acting_user_id`;')
await queryFn('ALTER TABLE `events` RENAME COLUMN `affected_user_id` TO `user_id`;')
await queryFn('RENAME TABLE `events` TO `event_protocol`;')
}

View File

@ -65,7 +65,9 @@ FEDERATION_COMMUNITY_URL=http://stage1.gradido.net
# the api port is the baseport, which will be added with the api-version, e.g. 1_0 = 5010 # the api port is the baseport, which will be added with the api-version, e.g. 1_0 = 5010
FEDERATION_COMMUNITY_API_PORT=5000 FEDERATION_COMMUNITY_API_PORT=5000
FEDERATION_CONFIG_VERSION=v1.2023-01-09
# comma separated list of api-versions, which cause starting several federation modules
FEDERATION_COMMUNITY_APIS=1_0,1_1,2_0
# database # database
DATABASE_CONFIG_VERSION=v1.2022-03-18 DATABASE_CONFIG_VERSION=v1.2022-03-18

View File

@ -0,0 +1,15 @@
location /api/$FEDERATION_APIVERSION {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:$FEDERATION_PORT;
proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.federation-$FEDERATION_PORT.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.federation-$FEDERATION_PORT.log warn;
}

View File

@ -42,19 +42,19 @@ server {
# Frontend (default) # Frontend (default)
location / { location / {
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade'; proxy_set_header Connection 'upgrade';
proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_pass http://127.0.0.1:3000; proxy_pass http://127.0.0.1:3000;
proxy_redirect off; proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log; access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn; error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn;
} }
# Backend # Backend
location /graphql { location /graphql {
@ -112,6 +112,9 @@ server {
error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn; error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn;
} }
# Federation
$FEDERATION_NGINX_CONF
# TODO this could be a performance optimization # TODO this could be a performance optimization
#location /vue { #location /vue {
# alias /var/www/html/gradido/frontend/dist; # alias /var/www/html/gradido/frontend/dist;

View File

@ -27,19 +27,19 @@ server {
# Frontend (default) # Frontend (default)
location / { location / {
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade'; proxy_set_header Connection 'upgrade';
proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_pass http://127.0.0.1:3000; proxy_pass http://127.0.0.1:3000;
proxy_redirect off; proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log; access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn; error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn;
} }
# Backend # Backend
location /graphql { location /graphql {
@ -98,6 +98,9 @@ server {
error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn; error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn;
} }
# Federation
$FEDERATION_NGINX_CONF
# TODO this could be a performance optimization # TODO this could be a performance optimization
#location /vue { #location /vue {
# alias /var/www/html/gradido/frontend/dist; # alias /var/www/html/gradido/frontend/dist;

View File

@ -59,8 +59,9 @@ ln -s /etc/nginx/sites-available/update-page.conf /etc/nginx/sites-enabled/
sudo /etc/init.d/nginx restart sudo /etc/init.d/nginx restart
# stop all services # stop all services
echo 'Stopping all Gradido services' >> $UPDATE_HTML echo 'Stop and delete all Gradido services' >> $UPDATE_HTML
pm2 stop all pm2 delete all
pm2 save
# git # git
BRANCH=${1:-master} BRANCH=${1:-master}
@ -73,12 +74,41 @@ git pull
export BUILD_COMMIT="$(git rev-parse HEAD)" export BUILD_COMMIT="$(git rev-parse HEAD)"
# Generate gradido.conf from template # Generate gradido.conf from template
# *** 1st prepare for each apiversion the federation conf for nginx from federation-template
# *** set FEDERATION_PORT from FEDERATION_COMMUNITY_APIS and create gradido-federation.conf file
rm -f $NGINX_CONFIG_DIR/gradido.conf.tmp
rm -f $NGINX_CONFIG_DIR/gradido-federation.conf.locations
echo "====================================================================================================" >> $UPDATE_HTML
IFS="," read -a API_ARRAY <<< $FEDERATION_COMMUNITY_APIS
for api in "${API_ARRAY[@]}"
do
export FEDERATION_APIVERSION=$api
# calculate port by remove '_' and add value of api to baseport
port=${api//_/}
FEDERATION_PORT=${FEDERATION_COMMUNITY_API_PORT:-5000}
FEDERATION_PORT=$(($FEDERATION_PORT + $port))
export FEDERATION_PORT
echo "create ngingx config: location /api/$FEDERATION_APIVERSION to http://127.0.0.1:$FEDERATION_PORT" >> $UPDATE_HTML
envsubst '$FEDERATION_APIVERSION, $FEDERATION_PORT' < $NGINX_CONFIG_DIR/gradido-federation.conf.template >> $NGINX_CONFIG_DIR/gradido-federation.conf.locations
done
unset FEDERATION_APIVERSION
unset FEDERATION_PORT
echo "====================================================================================================" >> $UPDATE_HTML
# *** 2nd read gradido-federation.conf file in env variable to be replaced in 3rd step
export FEDERATION_NGINX_CONF=$(< $NGINX_CONFIG_DIR/gradido-federation.conf.locations)
# *** 3rd generate gradido nginx config including federation modules per api-version
echo 'Generate new gradido nginx config' >> $UPDATE_HTML echo 'Generate new gradido nginx config' >> $UPDATE_HTML
case "$NGINX_SSL" in case "$NGINX_SSL" in
true) TEMPLATE_FILE="gradido.conf.ssl.template" ;; true) TEMPLATE_FILE="gradido.conf.ssl.template" ;;
*) TEMPLATE_FILE="gradido.conf.template" ;; *) TEMPLATE_FILE="gradido.conf.template" ;;
esac esac
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/gradido.conf envsubst '$FEDERATION_NGINX_CONF' < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/gradido.conf.tmp
unset FEDERATION_NGINX_CONF
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/gradido.conf.tmp > $NGINX_CONFIG_DIR/gradido.conf
rm $NGINX_CONFIG_DIR/gradido.conf.tmp
rm $NGINX_CONFIG_DIR/gradido-federation.conf.locations
# Generate update-page.conf from template # Generate update-page.conf from template
echo 'Generate new update-page nginx config' >> $UPDATE_HTML echo 'Generate new update-page nginx config' >> $UPDATE_HTML
@ -94,11 +124,13 @@ cp -f $PROJECT_ROOT/backend/.env $PROJECT_ROOT/backend/.env.bak
cp -f $PROJECT_ROOT/frontend/.env $PROJECT_ROOT/frontend/.env.bak cp -f $PROJECT_ROOT/frontend/.env $PROJECT_ROOT/frontend/.env.bak
cp -f $PROJECT_ROOT/admin/.env $PROJECT_ROOT/admin/.env.bak cp -f $PROJECT_ROOT/admin/.env $PROJECT_ROOT/admin/.env.bak
cp -f $PROJECT_ROOT/dht-node/.env $PROJECT_ROOT/dht-node/.env.bak cp -f $PROJECT_ROOT/dht-node/.env $PROJECT_ROOT/dht-node/.env.bak
cp -f $PROJECT_ROOT/federation/.env $PROJECT_ROOT/federation/.env.bak
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/database/.env.template > $PROJECT_ROOT/database/.env envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/database/.env.template > $PROJECT_ROOT/database/.env
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/federation/.env.template > $PROJECT_ROOT/federation/.env
# Install & build database # Install & build database
echo 'Updating database' >> $UPDATE_HTML echo 'Updating database' >> $UPDATE_HTML
@ -124,7 +156,6 @@ if [ "$DEPLOY_SEED_DATA" = "true" ]; then
fi fi
# TODO maybe handle this differently? # TODO maybe handle this differently?
export NODE_ENV=production export NODE_ENV=production
pm2 delete gradido-backend
pm2 start --name gradido-backend "yarn --cwd $PROJECT_ROOT/backend start" -l $GRADIDO_LOG_PATH/pm2.backend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' pm2 start --name gradido-backend "yarn --cwd $PROJECT_ROOT/backend start" -l $GRADIDO_LOG_PATH/pm2.backend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
pm2 save pm2 save
@ -137,7 +168,6 @@ yarn install
yarn build yarn build
# TODO maybe handle this differently? # TODO maybe handle this differently?
export NODE_ENV=production export NODE_ENV=production
pm2 delete gradido-frontend
pm2 start --name gradido-frontend "yarn --cwd $PROJECT_ROOT/frontend start" -l $GRADIDO_LOG_PATH/pm2.frontend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' pm2 start --name gradido-frontend "yarn --cwd $PROJECT_ROOT/frontend start" -l $GRADIDO_LOG_PATH/pm2.frontend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
pm2 save pm2 save
@ -150,7 +180,6 @@ yarn install
yarn build yarn build
# TODO maybe handle this differently? # TODO maybe handle this differently?
export NODE_ENV=production export NODE_ENV=production
pm2 delete gradido-admin
pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
pm2 save pm2 save
@ -163,15 +192,49 @@ yarn install
yarn build yarn build
# TODO maybe handle this differently? # TODO maybe handle this differently?
export NODE_ENV=production export NODE_ENV=production
pm2 delete gradido-dht-node
if [ ! -z $FEDERATION_DHT_TOPIC ]; then if [ ! -z $FEDERATION_DHT_TOPIC ]; then
pm2 start --name gradido-dht-node "yarn --cwd $PROJECT_ROOT/dht-node start" -l $GRADIDO_LOG_PATH/pm2.dht-node.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' pm2 start --name gradido-dht-node "yarn --cwd $PROJECT_ROOT/dht-node start" -l $GRADIDO_LOG_PATH/pm2.dht-node.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
pm2 save
else else
echo "=====================================================================" echo "=====================================================================" >> $UPDATE_HTML
echo "WARNING: FEDERATION_DHT_TOPIC not configured. DHT-Node not started..." echo "WARNING: FEDERATION_DHT_TOPIC not configured. DHT-Node not started..." >> $UPDATE_HTML
echo "=====================================================================" echo "=====================================================================" >> $UPDATE_HTML
fi fi
pm2 save
# Install & build federation
echo 'Updating federation' >> $UPDATE_HTML
cd $PROJECT_ROOT/federation
# TODO maybe handle this differently?
unset NODE_ENV
yarn install
yarn build
# TODO maybe handle this differently?
export NODE_ENV=production
# set FEDERATION_PORT from FEDERATION_COMMUNITY_APIS
IFS="," read -a API_ARRAY <<< $FEDERATION_COMMUNITY_APIS
for api in "${API_ARRAY[@]}"
do
export FEDERATION_API=$api
echo "FEDERATION_API=$FEDERATION_API" >> $UPDATE_HTML
export MODULENAME=gradido-federation-$api
echo "MODULENAME=$MODULENAME" >> $UPDATE_HTML
# calculate port by remove '_' and add value of api to baseport
port=${api//_/}
FEDERATION_PORT=${FEDERATION_COMMUNITY_API_PORT:-5000}
FEDERATION_PORT=$(($FEDERATION_PORT + $port))
export FEDERATION_PORT
echo "====================================================" >> $UPDATE_HTML
echo " start $MODULENAME listening on port=$FEDERATION_PORT" >> $UPDATE_HTML
echo "====================================================" >> $UPDATE_HTML
# pm2 delete $MODULENAME
pm2 start --name $MODULENAME "yarn --cwd $PROJECT_ROOT/federation start" -l $GRADIDO_LOG_PATH/pm2.$MODULENAME.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
pm2 save
done
# let nginx showing gradido # let nginx showing gradido
echo 'Configuring nginx to serve gradido again' >> $UPDATE_HTML echo 'Configuring nginx to serve gradido again' >> $UPDATE_HTML

View File

@ -3,7 +3,7 @@ import dotenv from 'dotenv'
dotenv.config() dotenv.config()
const constants = { const constants = {
DB_VERSION: '0060-update_communities_table', DB_VERSION: '0061-event_refactoring',
LOG4JS_CONFIG: 'log4js-config.json', LOG4JS_CONFIG: 'log4js-config.json',
// default log level on production should be info // default log level on production should be info
LOG_LEVEL: process.env.LOG_LEVEL || 'info', LOG_LEVEL: process.env.LOG_LEVEL || 'info',

View File

@ -719,11 +719,11 @@ describe('federation', () => {
JSON.stringify([ JSON.stringify([
{ {
api: '1_0', api: '1_0',
url: 'http://localhost:5001/api/', url: 'http://localhost/api/',
}, },
{ {
api: '2_0', api: '2_0',
url: 'http://localhost:5002/api/', url: 'http://localhost/api/',
}, },
]), ]),
), ),
@ -747,7 +747,7 @@ describe('federation', () => {
foreign: true, foreign: true,
publicKey: expect.any(Buffer), publicKey: expect.any(Buffer),
apiVersion: '1_0', apiVersion: '1_0',
endPoint: 'http://localhost:5001/api/', endPoint: 'http://localhost/api/',
lastAnnouncedAt: expect.any(Date), lastAnnouncedAt: expect.any(Date),
createdAt: expect.any(Date), createdAt: expect.any(Date),
updatedAt: null, updatedAt: null,
@ -764,7 +764,7 @@ describe('federation', () => {
foreign: true, foreign: true,
publicKey: expect.any(Buffer), publicKey: expect.any(Buffer),
apiVersion: '2_0', apiVersion: '2_0',
endPoint: 'http://localhost:5002/api/', endPoint: 'http://localhost/api/',
lastAnnouncedAt: expect.any(Date), lastAnnouncedAt: expect.any(Date),
createdAt: expect.any(Date), createdAt: expect.any(Date),
updatedAt: null, updatedAt: null,
@ -786,15 +786,15 @@ describe('federation', () => {
JSON.stringify([ JSON.stringify([
{ {
api: '1_0', api: '1_0',
url: 'http://localhost:5001/api/', url: 'http://localhost/api/',
}, },
{ {
api: '1_1', api: '1_1',
url: 'http://localhost:5002/api/', url: 'http://localhost/api/',
}, },
{ {
api: '2_0', api: '2_0',
url: 'http://localhost:5003/api/', url: 'http://localhost/api/',
}, },
]), ]),
), ),

View File

@ -181,11 +181,9 @@ export const startDHT = async (topic: string): Promise<void> => {
async function writeHomeCommunityEnries(pubKey: any): Promise<CommunityApi[]> { async function writeHomeCommunityEnries(pubKey: any): Promise<CommunityApi[]> {
const homeApiVersions: CommunityApi[] = Object.values(ApiVersionType).map(function (apiEnum) { const homeApiVersions: CommunityApi[] = Object.values(ApiVersionType).map(function (apiEnum) {
const port =
Number.parseInt(CONFIG.FEDERATION_COMMUNITY_API_PORT) + Number(apiEnum.replace('_', ''))
const comApi: CommunityApi = { const comApi: CommunityApi = {
api: apiEnum, api: apiEnum,
url: CONFIG.FEDERATION_COMMUNITY_URL + ':' + port.toString() + '/api/', url: CONFIG.FEDERATION_COMMUNITY_URL + '/api/',
} }
return comApi return comApi
}) })

11
federation/.env.dist Normal file
View File

@ -0,0 +1,11 @@
# Database
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=gradido_community
DB_USER=root
DB_PASSWORD=
# Federation
FEDERATION_API=1_0
FEDERATION_PORT=5010
FEDERATION_COMMUNITY_URL=http://localhost

16
federation/.env.template Normal file
View File

@ -0,0 +1,16 @@
CONFIG_VERSION=$FEDERATION_CONFIG_VERSION
LOG_LEVEL=$LOG_LEVEL
# this is set fix to false, because it is important for 'production' environments. only set to true if a graphql-playground should be in use
GRAPHIQL=false
# Database
DB_HOST=$DB_HOST
DB_PORT=$DB_PORT
DB_DATABASE=$DB_DATABASE
DB_USER=$DB_USER
DB_PASSWORD=$DB_PASSWORD
# Federation
FEDERATION_COMMUNITY_URL=$FEDERATION_COMMUNITY_URL

View File

@ -11,7 +11,7 @@ Decimal.set({
*/ */
const constants = { const constants = {
DB_VERSION: '0060-update_communities_table', DB_VERSION: '0061-event_refactoring',
// DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 // DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
LOG4JS_CONFIG: 'log4js-config.json', LOG4JS_CONFIG: 'log4js-config.json',
// default log level on production should be info // default log level on production should be info
@ -24,7 +24,6 @@ const constants = {
} }
const server = { const server = {
PORT: process.env.PORT || 5010,
// JWT_SECRET: process.env.JWT_SECRET || 'secret123', // JWT_SECRET: process.env.JWT_SECRET || 'secret123',
// JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m', // JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m',
GRAPHIQL: process.env.GRAPHIQL === 'true' || false, GRAPHIQL: process.env.GRAPHIQL === 'true' || false,
@ -40,21 +39,6 @@ const database = {
TYPEORM_LOGGING_RELATIVE_PATH: TYPEORM_LOGGING_RELATIVE_PATH:
process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.backend.log', process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.backend.log',
} }
/*
const community = {
COMMUNITY_NAME: process.env.COMMUNITY_NAME || 'Gradido Entwicklung',
COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/',
COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register',
COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}',
COMMUNITY_REDEEM_CONTRIBUTION_URL:
process.env.COMMUNITY_REDEEM_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}',
COMMUNITY_DESCRIPTION:
process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.',
}
*/
// This is needed by graphql-directive-auth
// process.env.APP_SECRET = server.JWT_SECRET
// Check config version // Check config version
constants.CONFIG_VERSION.CURRENT = constants.CONFIG_VERSION.CURRENT =
@ -71,10 +55,8 @@ if (
} }
const federation = { const federation = {
// FEDERATION_DHT_TOPIC: process.env.FEDERATION_DHT_TOPIC || null,
// FEDERATION_DHT_SEED: process.env.FEDERATION_DHT_SEED || null,
FEDERATION_PORT: process.env.FEDERATION_PORT || 5010,
FEDERATION_API: process.env.FEDERATION_API || '1_0', FEDERATION_API: process.env.FEDERATION_API || '1_0',
FEDERATION_PORT: process.env.FEDERATION_PORT || 5010,
FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL || null, FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL || null,
} }

View File

@ -0,0 +1,13 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Field, ObjectType } from 'type-graphql'
@ObjectType()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export class GetPublicKeyResult {
constructor(pubKey: string) {
this.publicKey = pubKey
}
@Field(() => String)
publicKey: string
}

View File

@ -0,0 +1,20 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Query, Resolver } from 'type-graphql'
import { federationLogger as logger } from '@/server/logger'
import { Community as DbCommunity } from '@entity/Community'
import { GetPublicKeyResult } from '../model/GetPublicKeyResult'
@Resolver()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export class PublicKeyResolver {
@Query(() => GetPublicKeyResult)
async getPublicKey(): Promise<GetPublicKeyResult> {
logger.info(`getPublicKey()...`)
const homeCom = await DbCommunity.findOneOrFail({
foreign: false,
apiVersion: '1_0',
})
logger.info(`getPublicKey()... with publicKey=${homeCom.publicKey}`)
return new GetPublicKeyResult(homeCom.publicKey.toString())
}
}

View File

@ -20,7 +20,7 @@ async function main() {
if (CONFIG.GRAPHIQL) { if (CONFIG.GRAPHIQL) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log( console.log(
`GraphIQL available at http://localhost:${CONFIG.FEDERATION_PORT}` `GraphIQL available at ${CONFIG.FEDERATION_COMMUNITY_URL}/api/${CONFIG.FEDERATION_API}`
) )
} }
}) })

View File

@ -7,6 +7,8 @@ FRONTEND_DIR="${PROJECT_DIR}/frontend/"
BACKEND_DIR="${PROJECT_DIR}/backend/" BACKEND_DIR="${PROJECT_DIR}/backend/"
DATABASE_DIR="${PROJECT_DIR}/database/" DATABASE_DIR="${PROJECT_DIR}/database/"
ADMIN_DIR="${PROJECT_DIR}/admin/" ADMIN_DIR="${PROJECT_DIR}/admin/"
DHTNODE_DIR="${PROJECT_DIR}/dht-node/"
FEDERATION_DIR="${PROJECT_DIR}/federation/"
# navigate to project directory # navigate to project directory
cd ${PROJECT_DIR} cd ${PROJECT_DIR}
@ -26,6 +28,10 @@ cd ${DATABASE_DIR}
yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION} yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION}
cd ${ADMIN_DIR} cd ${ADMIN_DIR}
yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION} yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION}
cd ${DHTNODE_DIR}
yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION}
cd ${FEDERATION_DIR}
yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${VERSION}
# generate changelog # generate changelog
cd ${PROJECT_DIR} cd ${PROJECT_DIR}