Merge pull request #2691 from gradido/event_protocol_rework

refactor(backend): event protocol rework
This commit is contained in:
Ulf Gebhardt 2023-02-14 17:11:34 +01:00 committed by GitHub
commit db236b1d34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 516 additions and 692 deletions

View File

@ -545,7 +545,7 @@ jobs:
report_name: Coverage Backend report_name: Coverage Backend
type: lcov type: lcov
result_path: ./backend/coverage/lcov.info result_path: ./backend/coverage/lcov.info
min_coverage: 78 min_coverage: 80
token: ${{ github.token }} token: ${{ github.token }}
########################################################################## ##########################################################################

View File

@ -1,509 +1,212 @@
import decimal from 'decimal.js-light' import { EventProtocol as DbEvent } from '@entity/EventProtocol'
import Decimal from 'decimal.js-light'
import { EventProtocolType } from './EventProtocolType' import { EventProtocolType } from './EventProtocolType'
export class EventBasic { export const Event = (
type: string type: EventProtocolType,
createdAt: Date
}
export class EventBasicUserId extends EventBasic {
userId: number
}
export class EventBasicTx extends EventBasicUserId {
transactionId: number
amount: decimal
}
export class EventBasicTxX extends EventBasicTx {
xUserId: number
xCommunityId: number
}
export class EventBasicCt extends EventBasicUserId {
contributionId: number
amount: decimal
}
export class EventBasicCtX extends EventBasicCt {
xUserId: number
xCommunityId: number
}
export class EventBasicRedeem extends EventBasicUserId {
transactionId?: number
contributionId?: number
}
export class EventBasicCtMsg extends EventBasicCt {
messageId: number
}
export class EventVisitGradido extends EventBasic {}
export class EventRegister extends EventBasicUserId {}
export class EventRedeemRegister extends EventBasicRedeem {}
export class EventVerifyRedeem extends EventBasicRedeem {}
export class EventInactiveAccount extends EventBasicUserId {}
export class EventSendConfirmationEmail extends EventBasicUserId {}
export class EventSendAccountMultiRegistrationEmail extends EventBasicUserId {}
export class EventSendForgotPasswordEmail extends EventBasicUserId {}
export class EventSendTransactionSendEmail extends EventBasicTxX {}
export class EventSendTransactionReceiveEmail extends EventBasicTxX {}
export class EventSendTransactionLinkRedeemEmail extends EventBasicTxX {}
export class EventSendAddedContributionEmail extends EventBasicCt {}
export class EventSendContributionConfirmEmail extends EventBasicCt {}
export class EventConfirmationEmail extends EventBasicUserId {}
export class EventRegisterEmailKlicktipp extends EventBasicUserId {}
export class EventLogin extends EventBasicUserId {}
export class EventLogout extends EventBasicUserId {}
export class EventRedeemLogin extends EventBasicRedeem {}
export class EventActivateAccount extends EventBasicUserId {}
export class EventPasswordChange extends EventBasicUserId {}
export class EventTransactionSend extends EventBasicTxX {}
export class EventTransactionSendRedeem extends EventBasicTxX {}
export class EventTransactionRepeateRedeem extends EventBasicTxX {}
export class EventTransactionCreation extends EventBasicTx {}
export class EventTransactionReceive extends EventBasicTxX {}
export class EventTransactionReceiveRedeem extends EventBasicTxX {}
export class EventContributionCreate extends EventBasicCt {}
export class EventAdminContributionCreate extends EventBasicCt {}
export class EventAdminContributionDelete extends EventBasicCt {}
export class EventAdminContributionDeny extends EventBasicCt {}
export class EventAdminContributionUpdate extends EventBasicCt {}
export class EventUserCreateContributionMessage extends EventBasicCtMsg {}
export class EventAdminCreateContributionMessage extends EventBasicCtMsg {}
export class EventContributionDelete extends EventBasicCt {}
export class EventContributionUpdate extends EventBasicCt {}
export class EventContributionConfirm extends EventBasicCtX {}
export class EventContributionDeny extends EventBasicCtX {}
export class EventContributionLinkDefine extends EventBasicCt {}
export class EventContributionLinkActivateRedeem extends EventBasicCt {}
export class EventDeleteUser extends EventBasicUserId {}
export class EventUndeleteUser extends EventBasicUserId {}
export class EventChangeUserRole extends EventBasicUserId {}
export class EventAdminUpdateContribution extends EventBasicCt {}
export class EventAdminDeleteContribution extends EventBasicCt {}
export class EventCreateContributionLink extends EventBasicCt {}
export class EventDeleteContributionLink extends EventBasicCt {}
export class EventUpdateContributionLink extends EventBasicCt {}
export class Event {
public setEventBasic(): Event {
this.type = EventProtocolType.BASIC
this.createdAt = new Date()
return this
}
public setEventVisitGradido(): Event {
this.setEventBasic()
this.type = EventProtocolType.VISIT_GRADIDO
return this
}
public setEventRegister(ev: EventRegister): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.REGISTER
return this
}
public setEventRedeemRegister(ev: EventRedeemRegister): Event {
this.setByBasicRedeem(ev.userId, ev.transactionId, ev.contributionId)
this.type = EventProtocolType.REDEEM_REGISTER
return this
}
public setEventVerifyRedeem(ev: EventVerifyRedeem): Event {
this.setByBasicRedeem(ev.userId, ev.transactionId, ev.contributionId)
this.type = EventProtocolType.VERIFY_REDEEM
return this
}
public setEventInactiveAccount(ev: EventInactiveAccount): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.INACTIVE_ACCOUNT
return this
}
public setEventSendConfirmationEmail(ev: EventSendConfirmationEmail): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.SEND_CONFIRMATION_EMAIL
return this
}
public setEventSendAccountMultiRegistrationEmail(
ev: EventSendAccountMultiRegistrationEmail,
): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL
return this
}
public setEventSendForgotPasswordEmail(ev: EventSendForgotPasswordEmail): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.SEND_FORGOT_PASSWORD_EMAIL
return this
}
public setEventSendTransactionSendEmail(ev: EventSendTransactionSendEmail): Event {
this.setByBasicTxX(ev.userId, ev.transactionId, ev.amount, ev.xUserId, ev.xCommunityId)
this.type = EventProtocolType.SEND_TRANSACTION_SEND_EMAIL
return this
}
public setEventSendTransactionReceiveEmail(ev: EventSendTransactionReceiveEmail): Event {
this.setByBasicTxX(ev.userId, ev.transactionId, ev.amount, ev.xUserId, ev.xCommunityId)
this.type = EventProtocolType.SEND_TRANSACTION_RECEIVE_EMAIL
return this
}
public setEventSendTransactionLinkRedeemEmail(ev: EventSendTransactionLinkRedeemEmail): Event {
this.setByBasicTxX(ev.userId, ev.transactionId, ev.amount, ev.xUserId, ev.xCommunityId)
this.type = EventProtocolType.SEND_TRANSACTION_LINK_REDEEM_EMAIL
return this
}
public setEventSendAddedContributionEmail(ev: EventSendAddedContributionEmail): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.SEND_ADDED_CONTRIBUTION_EMAIL
return this
}
public setEventSendContributionConfirmEmail(ev: EventSendContributionConfirmEmail): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.SEND_CONTRIBUTION_CONFIRM_EMAIL
return this
}
public setEventConfirmationEmail(ev: EventConfirmationEmail): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.CONFIRM_EMAIL
return this
}
public setEventRegisterEmailKlicktipp(ev: EventRegisterEmailKlicktipp): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.REGISTER_EMAIL_KLICKTIPP
return this
}
public setEventLogin(ev: EventLogin): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.LOGIN
return this
}
public setEventLogout(ev: EventLogout): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.LOGOUT
return this
}
public setEventRedeemLogin(ev: EventRedeemLogin): Event {
this.setByBasicRedeem(ev.userId, ev.transactionId, ev.contributionId)
this.type = EventProtocolType.REDEEM_LOGIN
return this
}
public setEventActivateAccount(ev: EventActivateAccount): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.ACTIVATE_ACCOUNT
return this
}
public setEventPasswordChange(ev: EventPasswordChange): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.PASSWORD_CHANGE
return this
}
public setEventTransactionSend(ev: EventTransactionSend): Event {
this.setByBasicTxX(ev.userId, ev.transactionId, ev.amount, ev.xUserId, ev.xCommunityId)
this.type = EventProtocolType.TRANSACTION_SEND
return this
}
public setEventTransactionSendRedeem(ev: EventTransactionSendRedeem): Event {
this.setByBasicTxX(ev.userId, ev.transactionId, ev.amount, ev.xUserId, ev.xCommunityId)
this.type = EventProtocolType.TRANSACTION_SEND_REDEEM
return this
}
public setEventTransactionRepeateRedeem(ev: EventTransactionRepeateRedeem): Event {
this.setByBasicTxX(ev.userId, ev.transactionId, ev.amount, ev.xUserId, ev.xCommunityId)
this.type = EventProtocolType.TRANSACTION_REPEATE_REDEEM
return this
}
public setEventTransactionCreation(ev: EventTransactionCreation): Event {
this.setByBasicTx(ev.userId, ev.transactionId, ev.amount)
this.type = EventProtocolType.TRANSACTION_CREATION
return this
}
public setEventTransactionReceive(ev: EventTransactionReceive): Event {
this.setByBasicTxX(ev.userId, ev.transactionId, ev.amount, ev.xUserId, ev.xCommunityId)
this.type = EventProtocolType.TRANSACTION_RECEIVE
return this
}
public setEventTransactionReceiveRedeem(ev: EventTransactionReceiveRedeem): Event {
this.setByBasicTxX(ev.userId, ev.transactionId, ev.amount, ev.xUserId, ev.xCommunityId)
this.type = EventProtocolType.TRANSACTION_RECEIVE_REDEEM
return this
}
public setEventContributionCreate(ev: EventContributionCreate): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.CONTRIBUTION_CREATE
return this
}
public setEventAdminContributionCreate(ev: EventAdminContributionCreate): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.ADMIN_CONTRIBUTION_CREATE
return this
}
public setEventAdminContributionDelete(ev: EventAdminContributionDelete): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.ADMIN_CONTRIBUTION_DELETE
return this
}
public setEventAdminContributionDeny(ev: EventAdminContributionDeny): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.ADMIN_CONTRIBUTION_DENY
return this
}
public setEventAdminContributionUpdate(ev: EventAdminContributionUpdate): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.ADMIN_CONTRIBUTION_UPDATE
return this
}
public setEventUserCreateContributionMessage(ev: EventUserCreateContributionMessage): Event {
this.setByBasicCtMsg(ev.userId, ev.contributionId, ev.amount, ev.messageId)
this.type = EventProtocolType.USER_CREATE_CONTRIBUTION_MESSAGE
return this
}
public setEventAdminCreateContributionMessage(ev: EventAdminCreateContributionMessage): Event {
this.setByBasicCtMsg(ev.userId, ev.contributionId, ev.amount, ev.messageId)
this.type = EventProtocolType.ADMIN_CREATE_CONTRIBUTION_MESSAGE
return this
}
public setEventContributionDelete(ev: EventContributionDelete): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.CONTRIBUTION_DELETE
return this
}
public setEventContributionUpdate(ev: EventContributionUpdate): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.CONTRIBUTION_UPDATE
return this
}
public setEventContributionConfirm(ev: EventContributionConfirm): Event {
this.setByBasicCtX(ev.userId, ev.contributionId, ev.amount, ev.xUserId, ev.xCommunityId)
this.type = EventProtocolType.CONTRIBUTION_CONFIRM
return this
}
public setEventContributionDeny(ev: EventContributionDeny): Event {
this.setByBasicCtX(ev.userId, ev.contributionId, ev.amount, ev.xUserId, ev.xCommunityId)
this.type = EventProtocolType.CONTRIBUTION_DENY
return this
}
public setEventContributionLinkDefine(ev: EventContributionLinkDefine): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.CONTRIBUTION_LINK_DEFINE
return this
}
public setEventContributionLinkActivateRedeem(ev: EventContributionLinkActivateRedeem): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM
return this
}
public setEventDeleteUser(ev: EventDeleteUser): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.DELETE_USER
return this
}
public setEventUndeleteUser(ev: EventUndeleteUser): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.UNDELETE_USER
return this
}
public setEventChangeUserRole(ev: EventChangeUserRole): Event {
this.setByBasicUser(ev.userId)
this.type = EventProtocolType.CHANGE_USER_ROLE
return this
}
public setEventAdminUpdateContribution(ev: EventAdminUpdateContribution): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.ADMIN_UPDATE_CONTRIBUTION
return this
}
public setEventAdminDeleteContribution(ev: EventAdminDeleteContribution): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.ADMIN_DELETE_CONTRIBUTION
return this
}
public setEventCreateContributionLink(ev: EventCreateContributionLink): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.CREATE_CONTRIBUTION_LINK
return this
}
public setEventDeleteContributionLink(ev: EventDeleteContributionLink): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.DELETE_CONTRIBUTION_LINK
return this
}
public setEventUpdateContributionLink(ev: EventUpdateContributionLink): Event {
this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
this.type = EventProtocolType.UPDATE_CONTRIBUTION_LINK
return this
}
setByBasicUser(userId: number): Event {
this.setEventBasic()
this.userId = userId
return this
}
setByBasicTx(userId: number, transactionId: number, amount: decimal): Event {
this.setByBasicUser(userId)
this.transactionId = transactionId
this.amount = amount
return this
}
setByBasicTxX(
userId: number, userId: number,
xUserId: number | null = null,
xCommunityId: number | null = null,
transactionId: number | null = null,
contributionId: number | null = null,
amount: Decimal | null = null,
messageId: number | null = null,
): DbEvent => {
const event = new DbEvent()
event.type = type
event.userId = userId
event.xUserId = xUserId
event.xCommunityId = xCommunityId
event.transactionId = transactionId
event.contributionId = contributionId
event.amount = amount
event.messageId = messageId
return event
}
export const EVENT_CONTRIBUTION_CREATE = async (
userId: number,
contributionId: number,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.CONTRIBUTION_CREATE,
userId,
null,
null,
null,
contributionId,
amount,
).save()
export const EVENT_CONTRIBUTION_DELETE = async (
userId: number,
contributionId: number,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.CONTRIBUTION_DELETE,
userId,
null,
null,
null,
contributionId,
amount,
).save()
export const EVENT_CONTRIBUTION_UPDATE = async (
userId: number,
contributionId: number,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.CONTRIBUTION_UPDATE,
userId,
null,
null,
null,
contributionId,
amount,
).save()
export const EVENT_ADMIN_CONTRIBUTION_CREATE = async (
userId: number,
contributionId: number,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.ADMIN_CONTRIBUTION_CREATE,
userId,
null,
null,
null,
contributionId,
amount,
).save()
export const EVENT_ADMIN_CONTRIBUTION_UPDATE = async (
userId: number,
contributionId: number,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
userId,
null,
null,
null,
contributionId,
amount,
).save()
export const EVENT_ADMIN_CONTRIBUTION_DELETE = async (
userId: number,
contributionId: number,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.ADMIN_CONTRIBUTION_DELETE,
userId,
null,
null,
null,
contributionId,
amount,
).save()
export const EVENT_CONTRIBUTION_CONFIRM = async (
userId: number,
contributionId: number,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.CONTRIBUTION_CONFIRM,
userId,
null,
null,
null,
contributionId,
amount,
).save()
export const EVENT_ADMIN_CONTRIBUTION_DENY = async (
userId: number,
xUserId: number,
contributionId: number,
amount: Decimal,
): Promise<DbEvent> =>
Event(
EventProtocolType.ADMIN_CONTRIBUTION_DENY,
userId,
xUserId,
null,
null,
contributionId,
amount,
).save()
export const EVENT_TRANSACTION_SEND = async (
userId: number,
xUserId: number,
transactionId: number, transactionId: number,
amount: decimal, amount: Decimal,
xUserId: number, ): Promise<DbEvent> =>
xCommunityId: number, Event(
): Event { EventProtocolType.TRANSACTION_SEND,
this.setByBasicTx(userId, transactionId, amount) userId,
this.xUserId = xUserId xUserId,
this.xCommunityId = xCommunityId null,
transactionId,
null,
amount,
).save()
return this export const EVENT_TRANSACTION_RECEIVE = async (
}
setByBasicCt(userId: number, contributionId: number, amount: decimal): Event {
this.setByBasicUser(userId)
this.contributionId = contributionId
this.amount = amount
return this
}
setByBasicCtMsg(
userId: number, userId: number,
contributionId: number,
amount: decimal,
messageId: number,
): Event {
this.setByBasicCt(userId, contributionId, amount)
this.messageId = messageId
return this
}
setByBasicCtX(
userId: number,
contributionId: number,
amount: decimal,
xUserId: number, xUserId: number,
xCommunityId: number, transactionId: number,
): Event { amount: Decimal,
this.setByBasicCt(userId, contributionId, amount) ): Promise<DbEvent> =>
this.xUserId = xUserId Event(
this.xCommunityId = xCommunityId EventProtocolType.TRANSACTION_RECEIVE,
userId,
xUserId,
null,
transactionId,
null,
amount,
).save()
return this export const EVENT_LOGIN = async (userId: number): Promise<DbEvent> =>
} Event(EventProtocolType.LOGIN, userId, null, null, null, null, null, null).save()
setByBasicRedeem(userId: number, transactionId?: number, contributionId?: number): Event { export const EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = async (
this.setByBasicUser(userId) userId: number,
if (transactionId) this.transactionId = transactionId ): Promise<DbEvent> => Event(EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL, userId).save()
if (contributionId) this.contributionId = contributionId
return this export const EVENT_SEND_CONFIRMATION_EMAIL = async (userId: number): Promise<DbEvent> =>
} Event(EventProtocolType.SEND_CONFIRMATION_EMAIL, userId).save()
id: number export const EVENT_ADMIN_SEND_CONFIRMATION_EMAIL = async (userId: number): Promise<DbEvent> =>
type: string Event(EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL, userId).save()
createdAt: Date
userId: number /* export const EVENT_REDEEM_REGISTER = async (
xUserId?: number userId: number,
xCommunityId?: number transactionId: number | null = null,
transactionId?: number contributionId: number | null = null,
contributionId?: number ): Promise<Event> =>
amount?: decimal Event(
messageId?: number EventProtocolType.REDEEM_REGISTER,
} userId,
null,
null,
transactionId,
contributionId,
).save()
*/
export const EVENT_REGISTER = async (userId: number): Promise<DbEvent> =>
Event(EventProtocolType.REGISTER, userId).save()
export const EVENT_ACTIVATE_ACCOUNT = async (userId: number): Promise<DbEvent> =>
Event(EventProtocolType.ACTIVATE_ACCOUNT, userId).save()

View File

@ -1,17 +0,0 @@
import { Event } from '@/event/Event'
import { backendLogger as logger } from '@/server/logger'
import { EventProtocol } from '@entity/EventProtocol'
export const writeEvent = async (event: Event): Promise<EventProtocol | null> => {
logger.info('writeEvent', event)
const dbEvent = new EventProtocol()
dbEvent.type = event.type
dbEvent.createdAt = event.createdAt
dbEvent.userId = event.userId
dbEvent.xUserId = event.xUserId || null
dbEvent.xCommunityId = event.xCommunityId || null
dbEvent.contributionId = event.contributionId || null
dbEvent.transactionId = event.transactionId || null
dbEvent.amount = event.amount || null
return dbEvent.save()
}

View File

@ -1,50 +1,50 @@
export enum EventProtocolType { export enum EventProtocolType {
BASIC = 'BASIC', // VISIT_GRADIDO = 'VISIT_GRADIDO',
VISIT_GRADIDO = 'VISIT_GRADIDO',
REGISTER = 'REGISTER', REGISTER = 'REGISTER',
REDEEM_REGISTER = 'REDEEM_REGISTER', REDEEM_REGISTER = 'REDEEM_REGISTER',
VERIFY_REDEEM = 'VERIFY_REDEEM', // VERIFY_REDEEM = 'VERIFY_REDEEM',
INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT', // INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT',
SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL', SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL',
ADMIN_SEND_CONFIRMATION_EMAIL = 'ADMIN_SEND_CONFIRMATION_EMAIL',
SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTIREGISTRATION_EMAIL', SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTIREGISTRATION_EMAIL',
CONFIRM_EMAIL = 'CONFIRM_EMAIL', // CONFIRM_EMAIL = 'CONFIRM_EMAIL',
REGISTER_EMAIL_KLICKTIPP = 'REGISTER_EMAIL_KLICKTIPP', // REGISTER_EMAIL_KLICKTIPP = 'REGISTER_EMAIL_KLICKTIPP',
LOGIN = 'LOGIN', LOGIN = 'LOGIN',
LOGOUT = 'LOGOUT', // LOGOUT = 'LOGOUT',
REDEEM_LOGIN = 'REDEEM_LOGIN', // REDEEM_LOGIN = 'REDEEM_LOGIN',
ACTIVATE_ACCOUNT = 'ACTIVATE_ACCOUNT', ACTIVATE_ACCOUNT = 'ACTIVATE_ACCOUNT',
SEND_FORGOT_PASSWORD_EMAIL = 'SEND_FORGOT_PASSWORD_EMAIL', // SEND_FORGOT_PASSWORD_EMAIL = 'SEND_FORGOT_PASSWORD_EMAIL',
PASSWORD_CHANGE = 'PASSWORD_CHANGE', // PASSWORD_CHANGE = 'PASSWORD_CHANGE',
SEND_TRANSACTION_SEND_EMAIL = 'SEND_TRANSACTION_SEND_EMAIL', // SEND_TRANSACTION_SEND_EMAIL = 'SEND_TRANSACTION_SEND_EMAIL',
SEND_TRANSACTION_RECEIVE_EMAIL = 'SEND_TRANSACTION_RECEIVE_EMAIL', // SEND_TRANSACTION_RECEIVE_EMAIL = 'SEND_TRANSACTION_RECEIVE_EMAIL',
TRANSACTION_SEND = 'TRANSACTION_SEND', TRANSACTION_SEND = 'TRANSACTION_SEND',
TRANSACTION_SEND_REDEEM = 'TRANSACTION_SEND_REDEEM', // TRANSACTION_SEND_REDEEM = 'TRANSACTION_SEND_REDEEM',
TRANSACTION_REPEATE_REDEEM = 'TRANSACTION_REPEATE_REDEEM', // TRANSACTION_REPEATE_REDEEM = 'TRANSACTION_REPEATE_REDEEM',
TRANSACTION_CREATION = 'TRANSACTION_CREATION', // TRANSACTION_CREATION = 'TRANSACTION_CREATION',
TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE', TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE',
TRANSACTION_RECEIVE_REDEEM = 'TRANSACTION_RECEIVE_REDEEM', // TRANSACTION_RECEIVE_REDEEM = 'TRANSACTION_RECEIVE_REDEEM',
SEND_TRANSACTION_LINK_REDEEM_EMAIL = 'SEND_TRANSACTION_LINK_REDEEM_EMAIL', // SEND_TRANSACTION_LINK_REDEEM_EMAIL = 'SEND_TRANSACTION_LINK_REDEEM_EMAIL',
SEND_ADDED_CONTRIBUTION_EMAIL = 'SEND_ADDED_CONTRIBUTION_EMAIL', // SEND_ADDED_CONTRIBUTION_EMAIL = 'SEND_ADDED_CONTRIBUTION_EMAIL',
SEND_CONTRIBUTION_CONFIRM_EMAIL = 'SEND_CONTRIBUTION_CONFIRM_EMAIL', // SEND_CONTRIBUTION_CONFIRM_EMAIL = 'SEND_CONTRIBUTION_CONFIRM_EMAIL',
CONTRIBUTION_CREATE = 'CONTRIBUTION_CREATE', CONTRIBUTION_CREATE = 'CONTRIBUTION_CREATE',
CONTRIBUTION_CONFIRM = 'CONTRIBUTION_CONFIRM', CONTRIBUTION_CONFIRM = 'CONTRIBUTION_CONFIRM',
CONTRIBUTION_DENY = 'CONTRIBUTION_DENY', // CONTRIBUTION_DENY = 'CONTRIBUTION_DENY',
CONTRIBUTION_LINK_DEFINE = 'CONTRIBUTION_LINK_DEFINE', // CONTRIBUTION_LINK_DEFINE = 'CONTRIBUTION_LINK_DEFINE',
CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM', // CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM',
CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE', CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE',
CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE', CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE',
ADMIN_CONTRIBUTION_CREATE = 'ADMIN_CONTRIBUTION_CREATE', ADMIN_CONTRIBUTION_CREATE = 'ADMIN_CONTRIBUTION_CREATE',
ADMIN_CONTRIBUTION_DELETE = 'ADMIN_CONTRIBUTION_DELETE', ADMIN_CONTRIBUTION_DELETE = 'ADMIN_CONTRIBUTION_DELETE',
ADMIN_CONTRIBUTION_DENY = 'ADMIN_CONTRIBUTION_DENY', ADMIN_CONTRIBUTION_DENY = 'ADMIN_CONTRIBUTION_DENY',
ADMIN_CONTRIBUTION_UPDATE = 'ADMIN_CONTRIBUTION_UPDATE', ADMIN_CONTRIBUTION_UPDATE = 'ADMIN_CONTRIBUTION_UPDATE',
USER_CREATE_CONTRIBUTION_MESSAGE = 'USER_CREATE_CONTRIBUTION_MESSAGE', // USER_CREATE_CONTRIBUTION_MESSAGE = 'USER_CREATE_CONTRIBUTION_MESSAGE',
ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE', // ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE',
DELETE_USER = 'DELETE_USER', // DELETE_USER = 'DELETE_USER',
UNDELETE_USER = 'UNDELETE_USER', // UNDELETE_USER = 'UNDELETE_USER',
CHANGE_USER_ROLE = 'CHANGE_USER_ROLE', // CHANGE_USER_ROLE = 'CHANGE_USER_ROLE',
ADMIN_UPDATE_CONTRIBUTION = 'ADMIN_UPDATE_CONTRIBUTION', // ADMIN_UPDATE_CONTRIBUTION = 'ADMIN_UPDATE_CONTRIBUTION',
ADMIN_DELETE_CONTRIBUTION = 'ADMIN_DELETE_CONTRIBUTION', // ADMIN_DELETE_CONTRIBUTION = 'ADMIN_DELETE_CONTRIBUTION',
CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK', // CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK',
DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK', // DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK',
UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK', // UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK',
} }

View File

@ -244,7 +244,7 @@ describe('ContributionResolver', () => {
) )
}) })
it('stores the create contribution event in the database', async () => { it('stores the CONTRIBUTION_CREATE event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.CONTRIBUTION_CREATE, type: EventProtocolType.CONTRIBUTION_CREATE,
@ -696,7 +696,7 @@ describe('ContributionResolver', () => {
) )
}) })
it('stores the update contribution event in the database', async () => { it('stores the CONTRIBUTION_UPDATE event in the database', async () => {
bibi = await query({ bibi = await query({
query: login, query: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
@ -1263,7 +1263,7 @@ describe('ContributionResolver', () => {
).resolves.toBeTruthy() ).resolves.toBeTruthy()
}) })
it('stores the delete contribution event in the database', async () => { it('stores the CONTRIBUTION_DELETE event in the database', async () => {
const contribution = await mutate({ const contribution = await mutate({
mutation: createContribution, mutation: createContribution,
variables: { variables: {
@ -1780,7 +1780,7 @@ describe('ContributionResolver', () => {
) )
}) })
it('stores the admin create contribution event in the database', async () => { it('stores the ADMIN_CONTRIBUTION_CREATE event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ADMIN_CONTRIBUTION_CREATE, type: EventProtocolType.ADMIN_CONTRIBUTION_CREATE,
@ -2045,7 +2045,7 @@ describe('ContributionResolver', () => {
) )
}) })
it('stores the admin update contribution event in the database', async () => { it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE, type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
@ -2085,7 +2085,7 @@ describe('ContributionResolver', () => {
) )
}) })
it('stores the admin update contribution event in the database', async () => { it('stores the ADMIN_CONTRIBUTION_UPDATE event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE, type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE,
@ -2229,7 +2229,7 @@ describe('ContributionResolver', () => {
) )
}) })
it('stores the admin delete contribution event in the database', async () => { it('stores the ADMIN_CONTRIBUTION_DELETE event in the database', async () => {
await expect(EventProtocol.find()).resolves.toContainEqual( await expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ADMIN_CONTRIBUTION_DELETE, type: EventProtocolType.ADMIN_CONTRIBUTION_DELETE,
@ -2371,7 +2371,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(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.CONTRIBUTION_CONFIRM, type: EventProtocolType.CONTRIBUTION_CONFIRM,
@ -2403,7 +2403,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(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.SEND_CONFIRMATION_EMAIL, type: EventProtocolType.SEND_CONFIRMATION_EMAIL,

View File

@ -37,17 +37,15 @@ import {
} from './util/creations' } from './util/creations'
import { MEMO_MAX_CHARS, MEMO_MIN_CHARS, FULL_CREATION_AVAILABLE } from './const/const' import { MEMO_MAX_CHARS, MEMO_MIN_CHARS, FULL_CREATION_AVAILABLE } from './const/const'
import { import {
Event, EVENT_CONTRIBUTION_CREATE,
EventContributionCreate, EVENT_CONTRIBUTION_DELETE,
EventContributionDelete, EVENT_CONTRIBUTION_UPDATE,
EventContributionUpdate, EVENT_ADMIN_CONTRIBUTION_CREATE,
EventContributionConfirm, EVENT_ADMIN_CONTRIBUTION_UPDATE,
EventAdminContributionCreate, EVENT_ADMIN_CONTRIBUTION_DELETE,
EventAdminContributionDelete, EVENT_CONTRIBUTION_CONFIRM,
EventAdminContributionDeny, EVENT_ADMIN_CONTRIBUTION_DENY,
EventAdminContributionUpdate,
} from '@/event/Event' } from '@/event/Event'
import { writeEvent } from '@/event/EventProtocolEmitter'
import { calculateDecay } from '@/util/decay' import { calculateDecay } from '@/util/decay'
import { import {
sendContributionConfirmedEmail, sendContributionConfirmedEmail,
@ -75,8 +73,6 @@ export class ContributionResolver {
throw new LogError('Memo text is too long', memo.length) throw new LogError('Memo text is too long', memo.length)
} }
const event = new Event()
const user = getUser(context) const user = getUser(context)
const creations = await getUserCreation(user.id, clientTimezoneOffset) const creations = await getUserCreation(user.id, clientTimezoneOffset)
logger.trace('creations', creations) logger.trace('creations', creations)
@ -95,11 +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)
const eventCreateContribution = new EventContributionCreate() await EVENT_CONTRIBUTION_CREATE(user.id, contribution.id, amount)
eventCreateContribution.userId = user.id
eventCreateContribution.amount = amount
eventCreateContribution.contributionId = contribution.id
await writeEvent(event.setEventContributionCreate(eventCreateContribution))
return new UnconfirmedContribution(contribution, user, creations) return new UnconfirmedContribution(contribution, user, creations)
} }
@ -110,7 +102,6 @@ export class ContributionResolver {
@Arg('id', () => Int) id: number, @Arg('id', () => Int) id: number,
@Ctx() context: Context, @Ctx() context: Context,
): Promise<boolean> { ): Promise<boolean> {
const event = new Event()
const user = getUser(context) const user = getUser(context)
const contribution = await DbContribution.findOne(id) const contribution = await DbContribution.findOne(id)
if (!contribution) { if (!contribution) {
@ -128,11 +119,7 @@ export class ContributionResolver {
contribution.deletedAt = new Date() contribution.deletedAt = new Date()
await contribution.save() await contribution.save()
const eventDeleteContribution = new EventContributionDelete() await EVENT_CONTRIBUTION_DELETE(user.id, contribution.id, contribution.amount)
eventDeleteContribution.userId = user.id
eventDeleteContribution.contributionId = contribution.id
eventDeleteContribution.amount = contribution.amount
await writeEvent(event.setEventContributionDelete(eventDeleteContribution))
const res = await contribution.softRemove() const res = await contribution.softRemove()
return !!res return !!res
@ -279,13 +266,7 @@ export class ContributionResolver {
contributionToUpdate.updatedAt = new Date() contributionToUpdate.updatedAt = new Date()
DbContribution.save(contributionToUpdate) DbContribution.save(contributionToUpdate)
const event = new Event() await EVENT_CONTRIBUTION_UPDATE(user.id, contributionId, amount)
const eventUpdateContribution = new EventContributionUpdate()
eventUpdateContribution.userId = user.id
eventUpdateContribution.contributionId = contributionId
eventUpdateContribution.amount = amount
await writeEvent(event.setEventContributionUpdate(eventUpdateContribution))
return new UnconfirmedContribution(contributionToUpdate, user, creations) return new UnconfirmedContribution(contributionToUpdate, user, creations)
} }
@ -321,7 +302,6 @@ export class ContributionResolver {
) )
} }
const event = new Event()
const moderator = getUser(context) const moderator = getUser(context)
logger.trace('moderator: ', moderator.id) logger.trace('moderator: ', moderator.id)
const creations = await getUserCreation(emailContact.userId, clientTimezoneOffset) const creations = await getUserCreation(emailContact.userId, clientTimezoneOffset)
@ -343,11 +323,7 @@ export class ContributionResolver {
await DbContribution.save(contribution) await DbContribution.save(contribution)
const eventAdminCreateContribution = new EventAdminContributionCreate() await EVENT_ADMIN_CONTRIBUTION_CREATE(moderator.id, contribution.id, amount)
eventAdminCreateContribution.userId = moderator.id
eventAdminCreateContribution.amount = amount
eventAdminCreateContribution.contributionId = contribution.id
await writeEvent(event.setEventAdminContributionCreate(eventAdminCreateContribution))
return getUserCreation(emailContact.userId, clientTimezoneOffset) return getUserCreation(emailContact.userId, clientTimezoneOffset)
} }
@ -442,12 +418,7 @@ export class ContributionResolver {
result.creation = await getUserCreation(emailContact.user.id, clientTimezoneOffset) result.creation = await getUserCreation(emailContact.user.id, clientTimezoneOffset)
const event = new Event() await EVENT_ADMIN_CONTRIBUTION_UPDATE(emailContact.user.id, contributionToUpdate.id, amount)
const eventAdminContributionUpdate = new EventAdminContributionUpdate()
eventAdminContributionUpdate.userId = emailContact.user.id
eventAdminContributionUpdate.amount = amount
eventAdminContributionUpdate.contributionId = contributionToUpdate.id
await writeEvent(event.setEventAdminContributionUpdate(eventAdminContributionUpdate))
return result return result
} }
@ -518,12 +489,8 @@ export class ContributionResolver {
await contribution.save() await contribution.save()
const res = await contribution.softRemove() const res = await contribution.softRemove()
const event = new Event() await EVENT_ADMIN_CONTRIBUTION_DELETE(contribution.userId, contribution.id, contribution.amount)
const eventAdminContributionDelete = new EventAdminContributionDelete()
eventAdminContributionDelete.userId = contribution.userId
eventAdminContributionDelete.amount = contribution.amount
eventAdminContributionDelete.contributionId = contribution.id
await writeEvent(event.setEventAdminContributionDelete(eventAdminContributionDelete))
sendContributionDeletedEmail({ sendContributionDeletedEmail({
firstName: user.firstName, firstName: user.firstName,
lastName: user.lastName, lastName: user.lastName,
@ -635,12 +602,7 @@ export class ContributionResolver {
await queryRunner.release() await queryRunner.release()
} }
const event = new Event() await EVENT_CONTRIBUTION_CONFIRM(user.id, contribution.id, contribution.amount)
const eventContributionConfirm = new EventContributionConfirm()
eventContributionConfirm.userId = user.id
eventContributionConfirm.amount = contribution.amount
eventContributionConfirm.contributionId = contribution.id
await writeEvent(event.setEventContributionConfirm(eventContributionConfirm))
} finally { } finally {
releaseLock() releaseLock()
} }
@ -730,12 +692,12 @@ export class ContributionResolver {
contributionToUpdate.deniedAt = new Date() contributionToUpdate.deniedAt = new Date()
const res = await contributionToUpdate.save() const res = await contributionToUpdate.save()
const event = new Event() await EVENT_ADMIN_CONTRIBUTION_DENY(
const eventAdminContributionDeny = new EventAdminContributionDeny() contributionToUpdate.userId,
eventAdminContributionDeny.userId = contributionToUpdate.userId moderator.id,
eventAdminContributionDeny.amount = contributionToUpdate.amount contributionToUpdate.id,
eventAdminContributionDeny.contributionId = contributionToUpdate.id contributionToUpdate.amount,
await writeEvent(event.setEventAdminContributionDeny(eventAdminContributionDeny)) )
sendContributionDeniedEmail({ sendContributionDeniedEmail({
firstName: user.firstName, firstName: user.firstName,

View File

@ -334,7 +334,7 @@ describe('send coins', () => {
) )
}) })
it('stores the send transaction event in the database', async () => { it('stores the TRANSACTION_SEND event in the database', async () => {
// Find the exact transaction (sent one is the one with user[1] as user) // Find the exact transaction (sent one is the one with user[1] as user)
const transaction = await Transaction.find({ const transaction = await Transaction.find({
userId: user[1].id, userId: user[1].id,
@ -351,7 +351,7 @@ describe('send coins', () => {
) )
}) })
it('stores the receive event in the database', async () => { it('stores the TRANSACTION_RECEIVE event in the database', async () => {
// Find the exact transaction (received one is the one with user[0] as user) // Find the exact transaction (received one is the one with user[0] as user)
const transaction = await Transaction.find({ const transaction = await Transaction.find({
userId: user[0].id, userId: user[0].id,

View File

@ -29,8 +29,7 @@ import {
sendTransactionLinkRedeemedEmail, sendTransactionLinkRedeemedEmail,
sendTransactionReceivedEmail, sendTransactionReceivedEmail,
} from '@/emails/sendEmailVariants' } from '@/emails/sendEmailVariants'
import { Event, EventTransactionReceive, EventTransactionSend } from '@/event/Event' import { EVENT_TRANSACTION_RECEIVE, EVENT_TRANSACTION_SEND } from '@/event/Event'
import { writeEvent } from '@/event/EventProtocolEmitter'
import { BalanceResolver } from './BalanceResolver' import { BalanceResolver } from './BalanceResolver'
import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const'
@ -141,19 +140,19 @@ export const executeTransaction = async (
await queryRunner.commitTransaction() await queryRunner.commitTransaction()
logger.info(`commit Transaction successful...`) logger.info(`commit Transaction successful...`)
const eventTransactionSend = new EventTransactionSend() await EVENT_TRANSACTION_SEND(
eventTransactionSend.userId = transactionSend.userId transactionSend.userId,
eventTransactionSend.xUserId = transactionSend.linkedUserId transactionSend.linkedUserId,
eventTransactionSend.transactionId = transactionSend.id transactionSend.id,
eventTransactionSend.amount = transactionSend.amount.mul(-1) transactionSend.amount.mul(-1),
await writeEvent(new Event().setEventTransactionSend(eventTransactionSend)) )
const eventTransactionReceive = new EventTransactionReceive() await EVENT_TRANSACTION_RECEIVE(
eventTransactionReceive.userId = transactionReceive.userId transactionReceive.userId,
eventTransactionReceive.xUserId = transactionReceive.linkedUserId transactionReceive.linkedUserId,
eventTransactionReceive.transactionId = transactionReceive.id transactionReceive.id,
eventTransactionReceive.amount = transactionReceive.amount transactionReceive.amount,
await writeEvent(new Event().setEventTransactionReceive(eventTransactionReceive)) )
} catch (e) { } catch (e) {
await queryRunner.rollbackTransaction() await queryRunner.rollbackTransaction()
logger.error(`Transaction was not successful: ${e}`) logger.error(`Transaction was not successful: ${e}`)

View File

@ -19,6 +19,7 @@ import {
setUserRole, setUserRole,
deleteUser, deleteUser,
unDeleteUser, unDeleteUser,
sendActivationEmail,
} from '@/seeds/graphql/mutations' } from '@/seeds/graphql/mutations'
import { verifyLogin, queryOptIn, searchAdminUsers, searchUsers } from '@/seeds/graphql/queries' import { verifyLogin, queryOptIn, searchAdminUsers, searchUsers } from '@/seeds/graphql/queries'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
@ -175,6 +176,19 @@ describe('UserResolver', () => {
}) })
}) })
}) })
it('stores the REGISTER event in the database', async () => {
const userConatct = await UserContact.findOneOrFail(
{ email: 'peter@lustig.de' },
{ relations: ['user'] },
)
expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({
type: EventProtocolType.REGISTER,
userId: userConatct.user.id,
}),
)
})
}) })
describe('account activation email', () => { describe('account activation email', () => {
@ -196,7 +210,7 @@ describe('UserResolver', () => {
}) })
}) })
it('stores the send confirmation event in the database', () => { it('stores the SEND_CONFIRMATION_EMAIL event in the database', () => {
expect(EventProtocol.find()).resolves.toContainEqual( expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.SEND_CONFIRMATION_EMAIL, type: EventProtocolType.SEND_CONFIRMATION_EMAIL,
@ -206,7 +220,7 @@ describe('UserResolver', () => {
}) })
}) })
describe('email already exists', () => { describe('user already exists', () => {
let mutation: User let mutation: User
beforeAll(async () => { beforeAll(async () => {
mutation = await mutate({ mutation: createUser, variables }) mutation = await mutate({ mutation: createUser, variables })
@ -236,6 +250,19 @@ describe('UserResolver', () => {
}), }),
) )
}) })
it('stores the SEND_ACCOUNT_MULTIREGISTRATION_EMAIL event in the database', async () => {
const userConatct = await UserContact.findOneOrFail(
{ email: 'peter@lustig.de' },
{ relations: ['user'] },
)
expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({
type: EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL,
userId: userConatct.user.id,
}),
)
})
}) })
describe('unknown language', () => { describe('unknown language', () => {
@ -328,7 +355,7 @@ describe('UserResolver', () => {
) )
}) })
it('stores the account activated event in the database', () => { it('stores the ACTIVATE_ACCOUNT event in the database', () => {
expect(EventProtocol.find()).resolves.toContainEqual( expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.ACTIVATE_ACCOUNT, type: EventProtocolType.ACTIVATE_ACCOUNT,
@ -337,7 +364,7 @@ describe('UserResolver', () => {
) )
}) })
it('stores the redeem register event in the database', () => { it('stores the REDEEM_REGISTER event in the database', () => {
expect(EventProtocol.find()).resolves.toContainEqual( expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.REDEEM_REGISTER, type: EventProtocolType.REDEEM_REGISTER,
@ -421,7 +448,7 @@ 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(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.REDEEM_REGISTER, type: EventProtocolType.REDEEM_REGISTER,
@ -647,6 +674,19 @@ describe('UserResolver', () => {
it('sets the token in the header', () => { it('sets the token in the header', () => {
expect(headerPushMock).toBeCalledWith({ key: 'token', value: expect.any(String) }) expect(headerPushMock).toBeCalledWith({ key: 'token', value: expect.any(String) })
}) })
it('stores the LOGIN event in the database', async () => {
const userConatct = await UserContact.findOneOrFail(
{ email: 'bibi@bloxberg.de' },
{ relations: ['user'] },
)
expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({
type: EventProtocolType.LOGIN,
userId: userConatct.user.id,
}),
)
})
}) })
describe('user is in database and wrong password', () => { describe('user is in database and wrong password', () => {
@ -887,7 +927,7 @@ describe('UserResolver', () => {
) )
}) })
it('stores the login event in the database', () => { it('stores the LOGIN event in the database', () => {
expect(EventProtocol.find()).resolves.toContainEqual( expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({ expect.objectContaining({
type: EventProtocolType.LOGIN, type: EventProtocolType.LOGIN,
@ -1668,6 +1708,157 @@ describe('UserResolver', () => {
}) })
}) })
///
describe('sendActivationEmail', () => {
describe('unauthenticated', () => {
it('returns an error', async () => {
await expect(
mutate({ mutation: sendActivationEmail, variables: { email: 'bibi@bloxberg.de' } }),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
}),
)
})
})
describe('authenticated', () => {
describe('without admin rights', () => {
beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg)
await mutate({
mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
})
})
afterAll(async () => {
await cleanDB()
resetToken()
})
it('returns an error', async () => {
await expect(
mutate({ mutation: sendActivationEmail, variables: { email: 'bibi@bloxberg.de' } }),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
}),
)
})
})
describe('with admin rights', () => {
beforeAll(async () => {
admin = await userFactory(testEnv, peterLustig)
await mutate({
mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
})
})
afterAll(async () => {
await cleanDB()
resetToken()
})
describe('user does not exist', () => {
it('throws an error', async () => {
jest.clearAllMocks()
await expect(
mutate({ mutation: sendActivationEmail, variables: { email: 'INVALID' } }),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('No user with this credentials')],
}),
)
})
it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith('No user with this credentials', 'invalid')
})
})
describe('user is deleted', () => {
it('throws an error', async () => {
jest.clearAllMocks()
await userFactory(testEnv, stephenHawking)
await expect(
mutate({ mutation: sendActivationEmail, variables: { email: 'stephen@hawking.uk' } }),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('User with given email contact is deleted')],
}),
)
})
it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith(
'User with given email contact is deleted',
'stephen@hawking.uk',
)
})
})
describe('sendActivationEmail with success', () => {
beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg)
})
it('returns true', async () => {
const result = await mutate({
mutation: sendActivationEmail,
variables: { email: 'bibi@bloxberg.de' },
})
expect(result).toEqual(
expect.objectContaining({
data: {
sendActivationEmail: true,
},
}),
)
})
it('sends an account activation email', async () => {
const userConatct = await UserContact.findOneOrFail(
{ email: 'bibi@bloxberg.de' },
{ relations: ['user'] },
)
const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace(
/{optin}/g,
userConatct.emailVerificationCode.toString(),
).replace(/{code}/g, '')
expect(sendAccountActivationEmail).toBeCalledWith({
firstName: 'Bibi',
lastName: 'Bloxberg',
email: 'bibi@bloxberg.de',
language: 'de',
activationLink,
timeDurationObject: expect.objectContaining({
hours: expect.any(Number),
minutes: expect.any(Number),
}),
})
})
it('stores the ADMIN_SEND_CONFIRMATION_EMAIL event in the database', async () => {
const userConatct = await UserContact.findOneOrFail(
{ email: 'bibi@bloxberg.de' },
{ relations: ['user'] },
)
expect(EventProtocol.find()).resolves.toContainEqual(
expect.objectContaining({
type: EventProtocolType.ADMIN_SEND_CONFIRMATION_EMAIL,
userId: userConatct.user.id,
}),
)
})
})
})
})
})
describe('unDelete user', () => { describe('unDelete user', () => {
describe('unauthenticated', () => { describe('unauthenticated', () => {
it('returns an error', async () => { it('returns an error', async () => {

View File

@ -48,15 +48,14 @@ import { klicktippNewsletterStateMiddleware } from '@/middleware/klicktippMiddle
import { klicktippSignIn } from '@/apis/KlicktippController' import { klicktippSignIn } from '@/apis/KlicktippController'
import { RIGHTS } from '@/auth/RIGHTS' import { RIGHTS } from '@/auth/RIGHTS'
import { hasElopageBuys } from '@/util/hasElopageBuys' import { hasElopageBuys } from '@/util/hasElopageBuys'
import { writeEvent } from '@/event/EventProtocolEmitter'
import { import {
Event, Event,
EventLogin, EVENT_LOGIN,
EventRedeemRegister, EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL,
EventRegister, EVENT_SEND_CONFIRMATION_EMAIL,
EventSendAccountMultiRegistrationEmail, EVENT_REGISTER,
EventSendConfirmationEmail, EVENT_ACTIVATE_ACCOUNT,
EventActivateAccount, EVENT_ADMIN_SEND_CONFIRMATION_EMAIL,
} from '@/event/Event' } from '@/event/Event'
import { getUserCreations } from './util/creations' import { getUserCreations } from './util/creations'
import { isValidPassword } from '@/password/EncryptorUtils' import { isValidPassword } from '@/password/EncryptorUtils'
@ -64,6 +63,7 @@ import { FULL_CREATION_AVAILABLE } from './const/const'
import { encryptPassword, verifyPassword } from '@/password/PasswordEncryptor' import { encryptPassword, verifyPassword } from '@/password/PasswordEncryptor'
import { PasswordEncryptionType } from '../enum/PasswordEncryptionType' import { PasswordEncryptionType } from '../enum/PasswordEncryptionType'
import LogError from '@/server/LogError' import LogError from '@/server/LogError'
import { EventProtocolType } from '@/event/EventProtocolType'
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const sodium = require('sodium-native') const sodium = require('sodium-native')
@ -177,9 +177,8 @@ export class UserResolver {
key: 'token', key: 'token',
value: encode(dbUser.gradidoID), value: encode(dbUser.gradidoID),
}) })
const ev = new EventLogin()
ev.userId = user.id await EVENT_LOGIN(user.id)
writeEvent(new Event().setEventLogin(ev))
logger.info(`successful Login: ${JSON.stringify(user, null, 2)}`) logger.info(`successful Login: ${JSON.stringify(user, null, 2)}`)
return user return user
} }
@ -211,7 +210,6 @@ export class UserResolver {
) )
// TODO: wrong default value (should be null), how does graphql work here? Is it an required field? // TODO: wrong default value (should be null), how does graphql work here? Is it an required field?
// default int publisher_id = 0; // default int publisher_id = 0;
const event = new Event()
// Validate Language (no throw) // Validate Language (no throw)
if (!language || !isLanguage(language)) { if (!language || !isLanguage(language)) {
@ -249,9 +247,9 @@ export class UserResolver {
email, email,
language: foundUser.language, // use language of the emails owner for sending language: foundUser.language, // use language of the emails owner for sending
}) })
const eventSendAccountMultiRegistrationEmail = new EventSendAccountMultiRegistrationEmail()
eventSendAccountMultiRegistrationEmail.userId = foundUser.id await EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL(foundUser.id)
writeEvent(event.setEventSendConfirmationEmail(eventSendAccountMultiRegistrationEmail))
logger.info( logger.info(
`sendAccountMultiRegistrationEmail by ${firstName} ${lastName} to ${foundUser.firstName} ${foundUser.lastName} <${email}>`, `sendAccountMultiRegistrationEmail by ${firstName} ${lastName} to ${foundUser.firstName} ${foundUser.lastName} <${email}>`,
) )
@ -268,10 +266,7 @@ export class UserResolver {
const gradidoID = await newGradidoID() const gradidoID = await newGradidoID()
const eventRegister = new EventRegister() const eventRegisterRedeem = Event(EventProtocolType.REDEEM_REGISTER, 0)
const eventRedeemRegister = new EventRedeemRegister()
const eventSendConfirmEmail = new EventSendConfirmationEmail()
let dbUser = new DbUser() let dbUser = new DbUser()
dbUser.gradidoID = gradidoID dbUser.gradidoID = gradidoID
dbUser.firstName = firstName dbUser.firstName = firstName
@ -288,14 +283,14 @@ 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
eventRedeemRegister.contributionId = contributionLink.id eventRegisterRedeem.contributionId = contributionLink.id
} }
} 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
eventRedeemRegister.transactionId = transactionLink.id eventRegisterRedeem.transactionId = transactionLink.id
} }
} }
} }
@ -333,8 +328,8 @@ export class UserResolver {
timeDurationObject: getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME), timeDurationObject: getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME),
}) })
logger.info(`sendAccountActivationEmail of ${firstName}.${lastName} to ${email}`) logger.info(`sendAccountActivationEmail of ${firstName}.${lastName} to ${email}`)
eventSendConfirmEmail.userId = dbUser.id
writeEvent(event.setEventSendConfirmationEmail(eventSendConfirmEmail)) await EVENT_SEND_CONFIRMATION_EMAIL(dbUser.id)
if (!emailSent) { if (!emailSent) {
logger.debug(`Account confirmation link: ${activationLink}`) logger.debug(`Account confirmation link: ${activationLink}`)
@ -351,11 +346,10 @@ export class UserResolver {
logger.info('createUser() successful...') logger.info('createUser() successful...')
if (redeemCode) { if (redeemCode) {
eventRedeemRegister.userId = dbUser.id eventRegisterRedeem.userId = dbUser.id
await writeEvent(event.setEventRedeemRegister(eventRedeemRegister)) await eventRegisterRedeem.save()
} else { } else {
eventRegister.userId = dbUser.id await EVENT_REGISTER(dbUser.id)
await writeEvent(event.setEventRegister(eventRegister))
} }
return new User(dbUser) return new User(dbUser)
@ -458,8 +452,6 @@ export class UserResolver {
await queryRunner.connect() await queryRunner.connect()
await queryRunner.startTransaction('REPEATABLE READ') await queryRunner.startTransaction('REPEATABLE READ')
const event = new Event()
try { try {
// Save user // Save user
await queryRunner.manager.save(user).catch((error) => { await queryRunner.manager.save(user).catch((error) => {
@ -473,9 +465,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...')
const eventActivateAccount = new EventActivateAccount() await EVENT_ACTIVATE_ACCOUNT(user.id)
eventActivateAccount.userId = user.id
writeEvent(event.setEventActivateAccount(eventActivateAccount))
} 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)
@ -791,19 +781,12 @@ export class UserResolver {
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)
if (!user) { if (user.deletedAt || user.emailContact.deletedAt) {
throw new LogError('Could not find user to given email contact', email)
}
if (user.deletedAt) {
throw new LogError('User with given email contact is deleted', email) throw new LogError('User with given email contact is deleted', email)
} }
const emailContact = user.emailContact
if (emailContact.deletedAt) {
throw new LogError('The given email contact for this user is deleted', email)
}
emailContact.emailResendCount++ user.emailContact.emailResendCount++
await emailContact.save() await user.emailContact.save()
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const emailSent = await sendAccountActivationEmail({ const emailSent = await sendAccountActivationEmail({
@ -811,7 +794,7 @@ export class UserResolver {
lastName: user.lastName, lastName: user.lastName,
email, email,
language: user.language, language: user.language,
activationLink: activationLink(emailContact.emailVerificationCode), activationLink: activationLink(user.emailContact.emailVerificationCode),
timeDurationObject: getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME), timeDurationObject: getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME),
}) })
@ -819,10 +802,7 @@ export class UserResolver {
if (!emailSent) { if (!emailSent) {
logger.info(`Account confirmation link: ${activationLink}`) logger.info(`Account confirmation link: ${activationLink}`)
} else { } else {
const event = new Event() await EVENT_ADMIN_SEND_CONFIRMATION_EMAIL(user.id)
const eventSendConfirmationEmail = new EventSendConfirmationEmail()
eventSendConfirmationEmail.userId = user.id
await writeEvent(event.setEventSendConfirmationEmail(eventSendConfirmationEmail))
} }
return true return true

View File

@ -68,6 +68,12 @@ export const createUser = gql`
} }
` `
export const sendActivationEmail = gql`
mutation ($email: String!) {
sendActivationEmail(email: $email)
}
`
export const sendCoins = gql` export const sendCoins = gql`
mutation ($email: String!, $amount: Decimal!, $memo: String!) { mutation ($email: String!, $amount: Decimal!, $memo: String!) {
sendCoins(email: $email, amount: $amount, memo: $memo) sendCoins(email: $email, amount: $amount, memo: $memo)