mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'contribution-resolver-logs-and-events' into admin-resolver-events-and-logging
as new events were added in the branch being merged
This commit is contained in:
commit
3cfe266a05
@ -10,7 +10,7 @@ Decimal.set({
|
||||
})
|
||||
|
||||
const constants = {
|
||||
DB_VERSION: '0049-add_user_contacts_table',
|
||||
DB_VERSION: '0050-add_messageId_to_event_protocol',
|
||||
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
||||
LOG4JS_CONFIG: 'log4js-config.json',
|
||||
// default log level on production should be info
|
||||
|
||||
@ -11,48 +11,67 @@ export class EventBasicUserId extends EventBasic {
|
||||
}
|
||||
|
||||
export class EventBasicTx extends EventBasicUserId {
|
||||
xUserId: number
|
||||
xCommunityId: number
|
||||
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 EventBasicTx {}
|
||||
export class EventTransactionSendRedeem extends EventBasicTx {}
|
||||
export class EventTransactionRepeateRedeem extends EventBasicTx {}
|
||||
export class EventTransactionCreation extends EventBasicUserId {
|
||||
transactionId: number
|
||||
amount: decimal
|
||||
}
|
||||
export class EventTransactionReceive extends EventBasicTx {}
|
||||
export class EventTransactionReceiveRedeem extends EventBasicTx {}
|
||||
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 EventContributionConfirm extends EventBasicCt {
|
||||
xUserId: number
|
||||
xCommunityId: number
|
||||
}
|
||||
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 {}
|
||||
|
||||
@ -100,6 +119,13 @@ export class Event {
|
||||
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
|
||||
@ -118,7 +144,49 @@ export class Event {
|
||||
ev: EventSendAccountMultiRegistrationEmail,
|
||||
): Event {
|
||||
this.setByBasicUser(ev.userId)
|
||||
this.type = EventProtocolType.SEND_ACCOUNT_MULTI_REGISTRATION_EMAIL
|
||||
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
|
||||
}
|
||||
@ -144,6 +212,13 @@ export class Event {
|
||||
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
|
||||
@ -166,44 +241,42 @@ export class Event {
|
||||
}
|
||||
|
||||
public setEventTransactionSend(ev: EventTransactionSend): Event {
|
||||
this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount)
|
||||
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.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount)
|
||||
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.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount)
|
||||
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.setByBasicUser(ev.userId)
|
||||
if (ev.transactionId) this.transactionId = ev.transactionId
|
||||
if (ev.amount) this.amount = ev.amount
|
||||
this.setByBasicTx(ev.userId, ev.transactionId, ev.amount)
|
||||
this.type = EventProtocolType.TRANSACTION_CREATION
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
public setEventTransactionReceive(ev: EventTransactionReceive): Event {
|
||||
this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount)
|
||||
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.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount)
|
||||
this.setByBasicTxX(ev.userId, ev.transactionId, ev.amount, ev.xUserId, ev.xCommunityId)
|
||||
this.type = EventProtocolType.TRANSACTION_RECEIVE_REDEEM
|
||||
|
||||
return this
|
||||
@ -216,15 +289,48 @@ export class Event {
|
||||
return this
|
||||
}
|
||||
|
||||
public setEventContributionConfirm(ev: EventContributionConfirm): Event {
|
||||
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)
|
||||
if (ev.xUserId) this.xUserId = ev.xUserId
|
||||
if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId
|
||||
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.xUserId, ev.xCommunityId, ev.contributionId, ev.amount)
|
||||
this.type = EventProtocolType.CONTRIBUTION_CONFIRM
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
public setEventContributionDeny(ev: EventContributionDeny): Event {
|
||||
this.setByBasicCtX(ev.userId, ev.xUserId, ev.xCommunityId, ev.contributionId, ev.amount)
|
||||
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
|
||||
@ -246,26 +352,58 @@ export class Event {
|
||||
return this
|
||||
}
|
||||
|
||||
setByBasicTx(
|
||||
userId: number,
|
||||
xUserId?: number,
|
||||
xCommunityId?: number,
|
||||
transactionId?: number,
|
||||
amount?: decimal,
|
||||
): Event {
|
||||
setByBasicTx(userId: number, transactionId: number, amount: decimal): Event {
|
||||
this.setByBasicUser(userId)
|
||||
if (xUserId) this.xUserId = xUserId
|
||||
if (xCommunityId) this.xCommunityId = xCommunityId
|
||||
if (transactionId) this.transactionId = transactionId
|
||||
if (amount) this.amount = amount
|
||||
this.transactionId = transactionId
|
||||
this.amount = amount
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
setByBasicCt(userId: number, contributionId: number, amount?: decimal): Event {
|
||||
setByBasicTxX(
|
||||
userId: number,
|
||||
transactionId: number,
|
||||
amount: decimal,
|
||||
xUserId: number,
|
||||
xCommunityId: number,
|
||||
): Event {
|
||||
this.setByBasicTx(userId, transactionId, amount)
|
||||
this.xUserId = xUserId
|
||||
this.xCommunityId = xCommunityId
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
setByBasicCt(userId: number, contributionId: number, amount: decimal): Event {
|
||||
this.setByBasicUser(userId)
|
||||
if (contributionId) this.contributionId = contributionId
|
||||
if (amount) this.amount = amount
|
||||
this.contributionId = contributionId
|
||||
this.amount = amount
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
setByBasicCtMsg(
|
||||
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,
|
||||
xCommunityId: number,
|
||||
): Event {
|
||||
this.setByBasicCt(userId, contributionId, amount)
|
||||
this.xUserId = xUserId
|
||||
this.xCommunityId = xCommunityId
|
||||
|
||||
return this
|
||||
}
|
||||
@ -278,27 +416,6 @@ export class Event {
|
||||
return this
|
||||
}
|
||||
|
||||
setByEventTransactionCreation(event: EventTransactionCreation): Event {
|
||||
this.type = event.type
|
||||
this.createdAt = event.createdAt
|
||||
this.userId = event.userId
|
||||
this.transactionId = event.transactionId
|
||||
this.amount = event.amount
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
setByEventContributionConfirm(event: EventContributionConfirm): Event {
|
||||
this.type = event.type
|
||||
this.createdAt = event.createdAt
|
||||
this.userId = event.userId
|
||||
this.xUserId = event.xUserId
|
||||
this.xCommunityId = event.xCommunityId
|
||||
this.amount = event.amount
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
id: number
|
||||
type: string
|
||||
createdAt: Date
|
||||
@ -308,4 +425,5 @@ export class Event {
|
||||
transactionId?: number
|
||||
contributionId?: number
|
||||
amount?: decimal
|
||||
messageId?: number
|
||||
}
|
||||
|
||||
@ -3,23 +3,36 @@ export enum EventProtocolType {
|
||||
VISIT_GRADIDO = 'VISIT_GRADIDO',
|
||||
REGISTER = 'REGISTER',
|
||||
REDEEM_REGISTER = 'REDEEM_REGISTER',
|
||||
VERIFY_REDEEM = 'VERIFY_REDEEM',
|
||||
INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT',
|
||||
SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL',
|
||||
SEND_ACCOUNT_MULTI_REGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTI_REGISTRATION_EMAIL',
|
||||
SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTIREGISTRATION_EMAIL',
|
||||
CONFIRM_EMAIL = 'CONFIRM_EMAIL',
|
||||
REGISTER_EMAIL_KLICKTIPP = 'REGISTER_EMAIL_KLICKTIPP',
|
||||
LOGIN = 'LOGIN',
|
||||
LOGOUT = 'LOGOUT',
|
||||
REDEEM_LOGIN = 'REDEEM_LOGIN',
|
||||
ACTIVATE_ACCOUNT = 'ACTIVATE_ACCOUNT',
|
||||
SEND_FORGOT_PASSWORD_EMAIL = 'SEND_FORGOT_PASSWORD_EMAIL',
|
||||
PASSWORD_CHANGE = 'PASSWORD_CHANGE',
|
||||
SEND_TRANSACTION_SEND_EMAIL = 'SEND_TRANSACTION_SEND_EMAIL',
|
||||
SEND_TRANSACTION_RECEIVE_EMAIL = 'SEND_TRANSACTION_RECEIVE_EMAIL',
|
||||
TRANSACTION_SEND = 'TRANSACTION_SEND',
|
||||
TRANSACTION_SEND_REDEEM = 'TRANSACTION_SEND_REDEEM',
|
||||
TRANSACTION_REPEATE_REDEEM = 'TRANSACTION_REPEATE_REDEEM',
|
||||
TRANSACTION_CREATION = 'TRANSACTION_CREATION',
|
||||
TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE',
|
||||
TRANSACTION_RECEIVE_REDEEM = 'TRANSACTION_RECEIVE_REDEEM',
|
||||
SEND_TRANSACTION_LINK_REDEEM_EMAIL = 'SEND_TRANSACTION_LINK_REDEEM_EMAIL',
|
||||
SEND_ADDED_CONTRIBUTION_EMAIL = 'SEND_ADDED_CONTRIBUTION_EMAIL',
|
||||
SEND_CONTRIBUTION_CONFIRM_EMAIL = 'SEND_CONTRIBUTION_CONFIRM_EMAIL',
|
||||
CONTRIBUTION_CREATE = 'CONTRIBUTION_CREATE',
|
||||
CONTRIBUTION_CONFIRM = 'CONTRIBUTION_CONFIRM',
|
||||
CONTRIBUTION_DENY = 'CONTRIBUTION_DENY',
|
||||
CONTRIBUTION_LINK_DEFINE = 'CONTRIBUTION_LINK_DEFINE',
|
||||
CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM',
|
||||
CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE',
|
||||
CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE',
|
||||
USER_CREATE_CONTRIBUTION_MESSAGE = 'USER_CREATE_CONTRIBUTION_MESSAGE',
|
||||
ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE',
|
||||
}
|
||||
|
||||
@ -16,6 +16,9 @@ import { userFactory } from '@/seeds/factory/user'
|
||||
import { creationFactory } from '@/seeds/factory/creation'
|
||||
import { creations } from '@/seeds/creation/index'
|
||||
import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||
import { EventProtocol } from '@entity/EventProtocol'
|
||||
import { EventProtocolType } from '@/event/EventProtocolType'
|
||||
import { logger } from '@test/testSetup'
|
||||
|
||||
let mutate: any, query: any, con: any
|
||||
let testEnv: any
|
||||
@ -35,6 +38,8 @@ afterAll(async () => {
|
||||
})
|
||||
|
||||
describe('ContributionResolver', () => {
|
||||
let bibi: any
|
||||
|
||||
describe('createContribution', () => {
|
||||
describe('unauthenticated', () => {
|
||||
it('returns an error', async () => {
|
||||
@ -54,7 +59,7 @@ describe('ContributionResolver', () => {
|
||||
describe('authenticated with valid user', () => {
|
||||
beforeAll(async () => {
|
||||
await userFactory(testEnv, bibiBloxberg)
|
||||
await query({
|
||||
bibi = await query({
|
||||
query: login,
|
||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||
})
|
||||
@ -84,6 +89,10 @@ describe('ContributionResolver', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith(`memo text is too short: memo.length=4 < (5)`)
|
||||
})
|
||||
|
||||
it('throws error when memo length greater than 255 chars', async () => {
|
||||
const date = new Date()
|
||||
await expect(
|
||||
@ -102,6 +111,10 @@ describe('ContributionResolver', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith(`memo text is too long: memo.length=259 > (255)`)
|
||||
})
|
||||
|
||||
it('throws error when creationDate not-valid', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
@ -121,6 +134,13 @@ describe('ContributionResolver', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'No information for available creations with the given creationDate=',
|
||||
'Invalid Date',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws error when creationDate 3 month behind', async () => {
|
||||
const date = new Date()
|
||||
await expect(
|
||||
@ -140,6 +160,13 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'No information for available creations with the given creationDate=',
|
||||
'Invalid Date',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('valid input', () => {
|
||||
@ -165,6 +192,15 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('stores the create contribution event in the database', async () => {
|
||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.CONTRIBUTION_CREATE,
|
||||
userId: bibi.data.login.id,
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -347,6 +383,10 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith('No contribution found to given id')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Memo length smaller than 5 chars', () => {
|
||||
@ -368,6 +408,10 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith('memo text is too short: memo.length=4 < (5)')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Memo length greater than 255 chars', () => {
|
||||
@ -389,6 +433,10 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith('memo text is too long: memo.length=259 > (255)')
|
||||
})
|
||||
})
|
||||
|
||||
describe('wrong user tries to update the contribution', () => {
|
||||
@ -420,6 +468,12 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'user of the pending contribution and send user does not correspond',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('admin tries to update a user contribution', () => {
|
||||
@ -441,6 +495,8 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
// TODO check that the error is logged (need to modify AdminResolver, avoid conflicts)
|
||||
})
|
||||
|
||||
describe('update too much so that the limit is exceeded', () => {
|
||||
@ -472,6 +528,12 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'The amount (1019 GDD) to be created exceeds the amount (1000 GDD) still available for this month.',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('update creation to a date that is older than 3 months', () => {
|
||||
@ -495,6 +557,13 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'No information for available creations with the given creationDate=',
|
||||
'Invalid Date',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('valid input', () => {
|
||||
@ -521,6 +590,15 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('stores the update contribution event in the database', async () => {
|
||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.CONTRIBUTION_UPDATE,
|
||||
contributionId: result.data.createContribution.id,
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -664,9 +742,13 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith('Contribution not found for given id')
|
||||
})
|
||||
})
|
||||
|
||||
describe('other user sends a deleteContribtuion', () => {
|
||||
describe('other user sends a deleteContribution', () => {
|
||||
it('returns an error', async () => {
|
||||
await query({
|
||||
query: login,
|
||||
@ -685,6 +767,10 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith('Can not delete contribution of another user')
|
||||
})
|
||||
})
|
||||
|
||||
describe('User deletes own contribution', () => {
|
||||
@ -698,6 +784,31 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
).resolves.toBeTruthy()
|
||||
})
|
||||
|
||||
it('stores the delete contribution event in the database', async () => {
|
||||
const contribution = await mutate({
|
||||
mutation: createContribution,
|
||||
variables: {
|
||||
amount: 166.0,
|
||||
memo: 'Whatever contribution',
|
||||
creationDate: new Date().toString(),
|
||||
},
|
||||
})
|
||||
|
||||
await mutate({
|
||||
mutation: deleteContribution,
|
||||
variables: {
|
||||
id: contribution.data.createContribution.id,
|
||||
},
|
||||
})
|
||||
|
||||
await expect(EventProtocol.find()).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: EventProtocolType.CONTRIBUTION_DELETE,
|
||||
contributionId: contribution.data.createContribution.id,
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('User deletes already confirmed contribution', () => {
|
||||
@ -729,6 +840,10 @@ describe('ContributionResolver', () => {
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith('A confirmed contribution can not be deleted')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -13,6 +13,13 @@ import { Contribution, ContributionListResult } from '@model/Contribution'
|
||||
import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
|
||||
import { validateContribution, getUserCreation, updateCreations } from './util/creations'
|
||||
import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const'
|
||||
import {
|
||||
Event,
|
||||
EventContributionCreate,
|
||||
EventContributionDelete,
|
||||
EventContributionUpdate,
|
||||
} from '@/event/Event'
|
||||
import { eventProtocol } from '@/event/EventProtocolEmitter'
|
||||
|
||||
@Resolver()
|
||||
export class ContributionResolver {
|
||||
@ -23,15 +30,17 @@ export class ContributionResolver {
|
||||
@Ctx() context: Context,
|
||||
): Promise<UnconfirmedContribution> {
|
||||
if (memo.length > MEMO_MAX_CHARS) {
|
||||
logger.error(`memo text is too long: memo.length=${memo.length} > (${MEMO_MAX_CHARS}`)
|
||||
logger.error(`memo text is too long: memo.length=${memo.length} > (${MEMO_MAX_CHARS})`)
|
||||
throw new Error(`memo text is too long (${MEMO_MAX_CHARS} characters maximum)`)
|
||||
}
|
||||
|
||||
if (memo.length < MEMO_MIN_CHARS) {
|
||||
logger.error(`memo text is too short: memo.length=${memo.length} < (${MEMO_MIN_CHARS}`)
|
||||
logger.error(`memo text is too short: memo.length=${memo.length} < (${MEMO_MIN_CHARS})`)
|
||||
throw new Error(`memo text is too short (${MEMO_MIN_CHARS} characters minimum)`)
|
||||
}
|
||||
|
||||
const event = new Event()
|
||||
|
||||
const user = getUser(context)
|
||||
const creations = await getUserCreation(user.id)
|
||||
logger.trace('creations', creations)
|
||||
@ -49,6 +58,13 @@ export class ContributionResolver {
|
||||
|
||||
logger.trace('contribution to save', contribution)
|
||||
await dbContribution.save(contribution)
|
||||
|
||||
const eventCreateContribution = new EventContributionCreate()
|
||||
eventCreateContribution.userId = user.id
|
||||
eventCreateContribution.amount = amount
|
||||
eventCreateContribution.contributionId = contribution.id
|
||||
await eventProtocol.writeEvent(event.setEventContributionCreate(eventCreateContribution))
|
||||
|
||||
return new UnconfirmedContribution(contribution, user, creations)
|
||||
}
|
||||
|
||||
@ -58,19 +74,32 @@ export class ContributionResolver {
|
||||
@Arg('id', () => Int) id: number,
|
||||
@Ctx() context: Context,
|
||||
): Promise<boolean> {
|
||||
const event = new Event()
|
||||
const user = getUser(context)
|
||||
const contribution = await dbContribution.findOne(id)
|
||||
if (!contribution) {
|
||||
logger.error('Contribution not found for given id')
|
||||
throw new Error('Contribution not found for given id.')
|
||||
}
|
||||
if (contribution.userId !== user.id) {
|
||||
logger.error('Can not delete contribution of another user')
|
||||
throw new Error('Can not delete contribution of another user')
|
||||
}
|
||||
if (contribution.confirmedAt) {
|
||||
logger.error('A confirmed contribution can not be deleted')
|
||||
throw new Error('A confirmed contribution can not be deleted')
|
||||
}
|
||||
|
||||
contribution.contributionStatus = ContributionStatus.DELETED
|
||||
contribution.deletedAt = new Date()
|
||||
await contribution.save()
|
||||
|
||||
const eventDeleteContribution = new EventContributionDelete()
|
||||
eventDeleteContribution.userId = user.id
|
||||
eventDeleteContribution.contributionId = contribution.id
|
||||
eventDeleteContribution.amount = contribution.amount
|
||||
await eventProtocol.writeEvent(event.setEventContributionDelete(eventDeleteContribution))
|
||||
|
||||
const res = await contribution.softRemove()
|
||||
return !!res
|
||||
}
|
||||
@ -154,9 +183,11 @@ export class ContributionResolver {
|
||||
where: { id: contributionId, confirmedAt: IsNull() },
|
||||
})
|
||||
if (!contributionToUpdate) {
|
||||
logger.error('No contribution found to given id')
|
||||
throw new Error('No contribution found to given id.')
|
||||
}
|
||||
if (contributionToUpdate.userId !== user.id) {
|
||||
logger.error('user of the pending contribution and send user does not correspond')
|
||||
throw new Error('user of the pending contribution and send user does not correspond')
|
||||
}
|
||||
|
||||
@ -174,6 +205,14 @@ export class ContributionResolver {
|
||||
contributionToUpdate.contributionStatus = ContributionStatus.PENDING
|
||||
dbContribution.save(contributionToUpdate)
|
||||
|
||||
const event = new Event()
|
||||
|
||||
const eventUpdateContribution = new EventContributionUpdate()
|
||||
eventUpdateContribution.userId = user.id
|
||||
eventUpdateContribution.contributionId = contributionId
|
||||
eventUpdateContribution.amount = amount
|
||||
await eventProtocol.writeEvent(event.setEventContributionUpdate(eventUpdateContribution))
|
||||
|
||||
return new UnconfirmedContribution(contributionToUpdate, user, creations)
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
|
||||
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
|
||||
|
||||
@Entity('event_protocol')
|
||||
export class EventProtocol extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ length: 100, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
type: string
|
||||
|
||||
@Column({ name: 'created_at', type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })
|
||||
createdAt: Date
|
||||
|
||||
@Column({ name: 'user_id', unsigned: true, nullable: false })
|
||||
userId: number
|
||||
|
||||
@Column({ name: 'x_user_id', unsigned: true, nullable: true })
|
||||
xUserId: number
|
||||
|
||||
@Column({ name: 'x_community_id', unsigned: true, nullable: true })
|
||||
xCommunityId: number
|
||||
|
||||
@Column({ name: 'transaction_id', unsigned: true, nullable: true })
|
||||
transactionId: number
|
||||
|
||||
@Column({ name: 'contribution_id', unsigned: true, nullable: true })
|
||||
contributionId: number
|
||||
|
||||
@Column({
|
||||
type: 'decimal',
|
||||
precision: 40,
|
||||
scale: 20,
|
||||
nullable: true,
|
||||
transformer: DecimalTransformer,
|
||||
})
|
||||
amount: Decimal
|
||||
|
||||
@Column({ name: 'message_id', unsigned: true, nullable: true })
|
||||
messageId: number
|
||||
}
|
||||
12
database/migrations/0050-add_messageId_to_event_protocol.ts
Normal file
12
database/migrations/0050-add_messageId_to_event_protocol.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/* 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(
|
||||
`ALTER TABLE \`event_protocol\` ADD COLUMN \`message_id\` int(10) unsigned NULL DEFAULT NULL;`,
|
||||
)
|
||||
}
|
||||
|
||||
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn(`ALTER TABLE \`event_protocol\` DROP COLUMN \`message_id\`;`)
|
||||
}
|
||||
@ -4,6 +4,12 @@
|
||||
# How to do this is described in detail in [setup.md](./setup.md)
|
||||
|
||||
# Find current directory & configure paths
|
||||
## For manualy use in terminal
|
||||
## set -o allexport
|
||||
## SCRIPT_DIR=$(pwd)
|
||||
## PROJECT_ROOT=$SCRIPT_DIR/../..
|
||||
## set +o allexport
|
||||
# Use here in script
|
||||
set -o allexport
|
||||
SCRIPT_PATH=$(realpath $0)
|
||||
SCRIPT_DIR=$(dirname $SCRIPT_PATH)
|
||||
@ -90,7 +96,7 @@ sudo certbot
|
||||
# Install logrotate
|
||||
sudo apt-get install -y logrotate
|
||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_DIR/logrotate/gradido.conf.template > $SCRIPT_DIR/logrotate/gradido.conf
|
||||
sudo mv $SCRIPT_DIR/logrotate/gradido.conf /etc/logrotate.d/gradido.conf
|
||||
sudo cp $SCRIPT_DIR/logrotate/gradido.conf.template /etc/logrotate.d/gradido.conf
|
||||
sudo chown root:root /etc/logrotate.d/gradido.conf
|
||||
|
||||
# Install mysql autobackup
|
||||
@ -137,4 +143,4 @@ envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.te
|
||||
# daily job: 0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null
|
||||
# Start gradido
|
||||
# Note: on first startup some errors will occur - nothing serious
|
||||
./start.sh
|
||||
./start.sh
|
||||
|
||||
@ -1,107 +1,233 @@
|
||||
# Setup script to setup the server be ready to run gradido
|
||||
# This assums you have root access via ssh to your cleanly setup server
|
||||
# Furthermore this assumes you have debian (11 64bit) running
|
||||
|
||||
# Check your (Sub-)Domain with your Provider.
|
||||
# In this document gddhost.tld refers to your chosen domain
|
||||
# Instructions To Run `Gradido` On Your Server
|
||||
|
||||
> ssh root@gddhost.tld
|
||||
We split setting up `Gradido` on your server into three steps:
|
||||
|
||||
# change root default shell
|
||||
> chsh -s /bin/bash
|
||||
# Create user `gradido`
|
||||
> useradd -d /home/gradido -m gradido
|
||||
> passwd gradido
|
||||
>> enter new password twice
|
||||
- [Preparing your server](#command-list-to-setup-your-server-be-ready-to-install-gradido)
|
||||
- [Installing `Gradido`](#use-commands-in-installsh-manually-in-your-shell-for-now)
|
||||
- [Crone-Job for `Gradido`](#define-cronjob-to-compensate-yarn-output-in-tmp)
|
||||
|
||||
# Gives the user priviledges - this might be omitted in order to harden security
|
||||
# Care: This will require another administering user if you don't want root access.
|
||||
# Since this setup expects the user running the software be the same as the administering user,
|
||||
# you have to adjust the instructions according to that scenario.
|
||||
# You might lock yourself out, if done wrong.
|
||||
> usermod -a -G sudo gradido
|
||||
## Command List To Setup Your Server Be Ready To Install `Gradido`
|
||||
|
||||
# change gradido default shell
|
||||
> chsh -s /bin/bash gradido
|
||||
# Install sudo
|
||||
> apt-get install sudo
|
||||
# switch to the new user
|
||||
> su gradido
|
||||
We assume you have root access via ssh to your cleanly setup server.
|
||||
Furthermore we assume you have debian (11 64bit) running.
|
||||
|
||||
# Register first ssh key for user `gradido`
|
||||
> mkdir ~/.ssh
|
||||
> chmod 700 ~/.ssh
|
||||
> nano ~/.ssh/authorized_keys
|
||||
>> insert public key
|
||||
>> ctrl + x
|
||||
>> save
|
||||
Check your (Sub-)Domain with your Provider.
|
||||
In this document `gddhost.tld` refers to your chosen domain.
|
||||
|
||||
# Test authentication via SSH
|
||||
> ssh -i /path/to/privKey gradido@gddhost.tld
|
||||
>> This should log you in and allow you to use sudo commands, which will require the user's password
|
||||
### SSH into your server
|
||||
|
||||
# Disable password authentication & root login
|
||||
> cd /etc/ssh
|
||||
> sudo cp sshd_config sshd_config.org
|
||||
> sudo nano sshd_config
|
||||
>> change `PermitRootLogin yes` to `PermitRootLogin no`
|
||||
>> change `#PasswordAuthentication yes` to `PasswordAuthentication no`
|
||||
>> change `UsePAM yes` to `UsePAM no`
|
||||
>> ctrl + x
|
||||
>> save
|
||||
> sudo /etc/init.d/ssh restart
|
||||
```bash
|
||||
ssh root@gddhost.tld
|
||||
```
|
||||
|
||||
# Test SSH Access only, no root ssh access
|
||||
> ssh gradido@gddhost.tld
|
||||
>> Will result in in either a password request for your key or the message `Permission denied (publickey)`
|
||||
> ssh -i /path/to/privKey root@gddhost.tld
|
||||
>> Will result in `Permission denied (publickey)`
|
||||
> ssh -i /path/to/privKey gradido@gddhost.tld
|
||||
>> Will succeed after entering the correct keys password (if any)
|
||||
### Change root default shell
|
||||
|
||||
# update system
|
||||
> sudo apt-get update
|
||||
> sudo apt-get upgrade
|
||||
```bash
|
||||
chsh -s /bin/bash
|
||||
```
|
||||
|
||||
# Install security tools
|
||||
## ufw
|
||||
> sudo apt-get install ufw
|
||||
> sudo ufw allow http
|
||||
> sudo ufw allow https
|
||||
> sudo ufw allow ssh
|
||||
> sudo ufw enable
|
||||
### Create user `gradido`
|
||||
|
||||
## fail2ban
|
||||
> sudo apt-get install -y fail2ban
|
||||
> sudo /etc/init.d/fail2ban restart
|
||||
```bash
|
||||
$ useradd -d /home/gradido -m gradido
|
||||
$ passwd gradido
|
||||
# enter new password twice
|
||||
```
|
||||
|
||||
# Install gradido
|
||||
> sudo apt-get install -y git
|
||||
> cd ~
|
||||
> git clone https://github.com/gradido/gradido.git
|
||||
### Give the user priviledges
|
||||
|
||||
# Timezone
|
||||
# Note: This is needed - since there is Summer-Time included in the default server Setup - UTC is REQUIRED for production data
|
||||
> sudo timedatectl set-timezone UTC
|
||||
# > sudo timedatectl set-ntp on
|
||||
# > sudo apt purge ntp
|
||||
# > sudo systemctl start systemd-timesyncd
|
||||
# >> timedatectl to verify
|
||||
This might be omitted in order to harden security.
|
||||
|
||||
# Adjust .env
|
||||
# NOTE ';' can not be part of any value
|
||||
# The Github Secret is Created on Github in Settimgs -> Webhooks
|
||||
> cd gradido/deployment/bare_metal
|
||||
> cp .env.dist .env
|
||||
> nano .env
|
||||
>> Adjust values accordingly
|
||||
# Define cronjob to compensate yarn output in /tmp
|
||||
> yarn creates output in /tmp directory, which must be deleted regularly and will be done per cronjob
|
||||
> on stage1 a hourly job is necessary by setting the following job in the crontab for the gradido user
|
||||
> crontab -e opens the crontab in edit-mode and insert the following entry:
|
||||
> "0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null"
|
||||
> on stage2 a daily job is necessary by setting the following job in the crontab for the gradido user
|
||||
> crontab -e opens the crontab in edit-mode and insert the following entry:
|
||||
> "0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null"
|
||||
# TODO the install.sh is not yet ready to run directly - consider to use it as pattern to do it manually
|
||||
> ./install.sh
|
||||
***!!! Attention !!!***
|
||||
|
||||
- Care: This will require another administering user if you don't want root access.
|
||||
- Since this setup expects the user running the software be the same as the administering user,
|
||||
- you have to adjust the instructions according to that scenario.
|
||||
- you might lock yourself out, if done wrong.
|
||||
|
||||
#### Add the new user `gradido` to `sudo` group
|
||||
|
||||
```bash
|
||||
usermod -a -G sudo gradido
|
||||
```
|
||||
|
||||
### Change gradido default shell
|
||||
|
||||
```bash
|
||||
chsh -s /bin/bash gradido
|
||||
```
|
||||
|
||||
### Install sudo
|
||||
|
||||
```bash
|
||||
apt-get install sudo
|
||||
```
|
||||
|
||||
### Switch to the new user
|
||||
|
||||
```bash
|
||||
su gradido
|
||||
```
|
||||
|
||||
### Register first ssh key for user `gradido`
|
||||
|
||||
```bash
|
||||
$ mkdir ~/.ssh
|
||||
$ chmod 700 ~/.ssh
|
||||
$ nano ~/.ssh/authorized_keys
|
||||
# insert public key
|
||||
# ctrl + x
|
||||
# save
|
||||
```
|
||||
|
||||
### Test authentication via SSH
|
||||
|
||||
If you logout from the server you can test authentication:
|
||||
|
||||
```bash
|
||||
$ ssh -i /path/to/privKey gradido@gddhost.tld
|
||||
# This should log you in and allow you to use sudo commands, which will require the user's password
|
||||
```
|
||||
|
||||
### Disable password authentication and root login
|
||||
|
||||
```bash
|
||||
$ cd /etc/ssh
|
||||
$ sudo cp sshd_config sshd_config.org
|
||||
$ sudo nano sshd_config
|
||||
# change 'PermitRootLogin yes' to `PermitRootLogin no`
|
||||
# change 'PasswordAuthentication yes' to 'PasswordAuthentication no'
|
||||
# change 'UsePAM yes' to 'UsePAM no'
|
||||
# ctrl + x
|
||||
# save
|
||||
$ sudo /etc/init.d/ssh restart
|
||||
```
|
||||
|
||||
### Test SSH Access only, no root ssh access
|
||||
|
||||
```bash
|
||||
$ ssh gradido@gddhost.tld
|
||||
# Will result in in either a passphrase request for your key or the message 'Permission denied (publickey)'
|
||||
$ ssh -i /path/to/privKey root@gddhost.tld
|
||||
# Will result in 'Permission denied (publickey)'
|
||||
$ ssh -i /path/to/privKey gradido@gddhost.tld
|
||||
# Will succeed after entering the correct keys passphrase (if any)
|
||||
```
|
||||
|
||||
### Update system
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade
|
||||
```
|
||||
|
||||
### Install security tools
|
||||
|
||||
#### Install: `ufw`
|
||||
|
||||
```bash
|
||||
sudo apt-get install ufw
|
||||
sudo ufw allow http
|
||||
sudo ufw allow https
|
||||
sudo ufw allow ssh
|
||||
sudo ufw enable
|
||||
```
|
||||
|
||||
#### Install: `fail2ban`
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y fail2ban
|
||||
sudo /etc/init.d/fail2ban restart
|
||||
```
|
||||
|
||||
### Install `Gradido` code
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y git
|
||||
cd ~
|
||||
git clone https://github.com/gradido/gradido.git
|
||||
```
|
||||
|
||||
### Timezone
|
||||
|
||||
*Note: This is needed - since there is Summer-Time included in the default server Setup - UTC is REQUIRED for production data.*
|
||||
|
||||
```bash
|
||||
sudo timedatectl set-timezone UTC
|
||||
sudo timedatectl set-ntp on
|
||||
sudo apt purge ntp
|
||||
sudo systemctl start systemd-timesyncd
|
||||
# timedatectl to verify
|
||||
```
|
||||
|
||||
### Adjust the values in `.env`
|
||||
|
||||
***!!! Attention !!!***
|
||||
|
||||
*Don't forget this step!
|
||||
All your following installations in `install.sh` will fail!*
|
||||
|
||||
*Notes:*
|
||||
|
||||
- *`;` cannot be part of any value!*
|
||||
- *The GitHub secret is created on GitHub in Settings -> Webhooks.*
|
||||
|
||||
#### Create `.env` and set values
|
||||
|
||||
```bash
|
||||
$ cd gradido/deployment/bare_metal
|
||||
$ cp .env.dist .env
|
||||
$ nano .env
|
||||
# adjust values accordingly
|
||||
```
|
||||
|
||||
## Use Commands In `install.sh` Manually In Your Shell For Now
|
||||
|
||||
The script `install.sh` is not yet ready to run directly.
|
||||
Use it as pattern to do all steps manually in your terminal shell.
|
||||
|
||||
*TODO: Bring the `install.sh` script to run in the shell.*
|
||||
|
||||
***!!! Attention !!!***
|
||||
|
||||
- *Commands in `install.sh`:*
|
||||
- *The commands for setting the paths in the used env variables are not working directly in the terminal, consider the out commented commands for this purpose.*
|
||||
|
||||
Follow the commands in `./install.sh` as installation pattern.
|
||||
|
||||
## Define Cronjob To Compensate Yarn Output In `/tmp`
|
||||
|
||||
`yarn` creates output in `/tmp` directory, which must be deleted regularly and will be done per Cron-Job.
|
||||
|
||||
### On `stage1`
|
||||
|
||||
An hourly job is necessary on `stage1` by setting the following job in the `crontab` for the `gradido` user.
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
crontab -e
|
||||
```
|
||||
|
||||
This opens the crontab in edit-mode and insert the following entry:
|
||||
|
||||
```bash
|
||||
0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null
|
||||
```
|
||||
|
||||
### On `stage2`
|
||||
|
||||
A daily job is necessary on `stage2` by setting the following job in the `crontab` for the `gradido` user.
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
crontab -e
|
||||
```
|
||||
|
||||
This opens the `crontab` in edit-mode and insert the following entry:
|
||||
|
||||
```bash
|
||||
0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null
|
||||
```
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user