mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into 1594-Show-if-a-transaction-was-created-by-link
This commit is contained in:
commit
1ae4aa4e85
7
.github/workflows/test.yml
vendored
7
.github/workflows/test.yml
vendored
@ -509,16 +509,13 @@ jobs:
|
|||||||
##########################################################################
|
##########################################################################
|
||||||
# UNIT TESTS BACKEND #####################################################
|
# UNIT TESTS BACKEND #####################################################
|
||||||
##########################################################################
|
##########################################################################
|
||||||
- name: backend | docker-compose
|
- name: backend | docker-compose mariadb
|
||||||
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb
|
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb
|
||||||
- name: Sleep for 30 seconds
|
- name: Sleep for 30 seconds
|
||||||
run: sleep 30s
|
run: sleep 30s
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: backend | docker-compose database
|
- name: backend | docker-compose database
|
||||||
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database
|
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps database
|
||||||
- name: Sleep for 30 seconds
|
|
||||||
run: sleep 30s
|
|
||||||
shell: bash
|
|
||||||
- name: backend Unit tests | test
|
- name: backend Unit tests | test
|
||||||
run: cd database && yarn && yarn build && cd ../backend && yarn && yarn test
|
run: cd database && yarn && yarn build && cd ../backend && yarn && yarn test
|
||||||
# run: docker-compose -f docker-compose.yml -f docker-compose.test.yml exec -T backend yarn test
|
# run: docker-compose -f docker-compose.yml -f docker-compose.test.yml exec -T backend yarn test
|
||||||
@ -531,7 +528,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: 48
|
min_coverage: 54
|
||||||
token: ${{ github.token }}
|
token: ${{ github.token }}
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|||||||
@ -60,12 +60,12 @@
|
|||||||
"typescript": "^4.3.4"
|
"typescript": "^4.3.4"
|
||||||
},
|
},
|
||||||
"_moduleAliases": {
|
"_moduleAliases": {
|
||||||
"@": "./src",
|
"@": "./build/src",
|
||||||
"@arg": "./src/graphql/arg",
|
"@arg": "./build/src/graphql/arg",
|
||||||
"@dbTools": "../database/build/src",
|
"@dbTools": "../database/build/src",
|
||||||
"@entity": "../database/build/entity",
|
"@entity": "../database/build/entity",
|
||||||
"@enum": "./src/graphql/enum",
|
"@enum": "./build/src/graphql/enum",
|
||||||
"@model": "./src/graphql/model",
|
"@model": "./build/src/graphql/model",
|
||||||
"@repository": "./src/typeorm/repository"
|
"@repository": "./build/src/typeorm/repository"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,35 +13,33 @@ import { ServerUser } from '@entity/ServerUser'
|
|||||||
const isAuthorized: AuthChecker<any> = async ({ context }, rights) => {
|
const isAuthorized: AuthChecker<any> = async ({ context }, rights) => {
|
||||||
context.role = ROLE_UNAUTHORIZED // unauthorized user
|
context.role = ROLE_UNAUTHORIZED // unauthorized user
|
||||||
|
|
||||||
|
// is rights an inalienable right?
|
||||||
|
if ((<RIGHTS[]>rights).reduce((acc, right) => acc && INALIENABLE_RIGHTS.includes(right), true))
|
||||||
|
return true
|
||||||
|
|
||||||
// Do we have a token?
|
// Do we have a token?
|
||||||
if (context.token) {
|
if (!context.token) {
|
||||||
// Decode the token
|
throw new Error('401 Unauthorized')
|
||||||
const decoded = decode(context.token)
|
}
|
||||||
if (!decoded) {
|
|
||||||
// Are all rights requested public?
|
// Decode the token
|
||||||
const isInalienable = (<RIGHTS[]>rights).reduce(
|
const decoded = decode(context.token)
|
||||||
(acc, right) => acc && INALIENABLE_RIGHTS.includes(right),
|
if (!decoded) {
|
||||||
true,
|
throw new Error('403.13 - Client certificate revoked')
|
||||||
)
|
}
|
||||||
if (isInalienable) {
|
// Set context pubKey
|
||||||
// If public dont throw and permit access
|
context.pubKey = Buffer.from(decoded.pubKey).toString('hex')
|
||||||
return true
|
|
||||||
} else {
|
// TODO - load from database dynamically & admin - maybe encode this in the token to prevent many database requests
|
||||||
// Throw on a protected route
|
// TODO this implementation is bullshit - two database queries cause our user identifiers are not aligned and vary between email, id and pubKey
|
||||||
throw new Error('403.13 - Client certificate revoked')
|
const userRepository = await getCustomRepository(UserRepository)
|
||||||
}
|
try {
|
||||||
}
|
|
||||||
// Set context pubKey
|
|
||||||
context.pubKey = Buffer.from(decoded.pubKey).toString('hex')
|
|
||||||
// set new header token
|
|
||||||
// TODO - load from database dynamically & admin - maybe encode this in the token to prevent many database requests
|
|
||||||
// TODO this implementation is bullshit - two database queries cause our user identifiers are not aligned and vary between email, id and pubKey
|
|
||||||
const userRepository = await getCustomRepository(UserRepository)
|
|
||||||
const user = await userRepository.findByPubkeyHex(context.pubKey)
|
const user = await userRepository.findByPubkeyHex(context.pubKey)
|
||||||
const countServerUsers = await ServerUser.count({ email: user.email })
|
const countServerUsers = await ServerUser.count({ email: user.email })
|
||||||
context.role = countServerUsers > 0 ? ROLE_ADMIN : ROLE_USER
|
context.role = countServerUsers > 0 ? ROLE_ADMIN : ROLE_USER
|
||||||
|
} catch {
|
||||||
context.setHeaders.push({ key: 'token', value: encode(decoded.pubKey) })
|
// in case the database query fails (user deleted)
|
||||||
|
throw new Error('401 Unauthorized')
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for correct rights
|
// check for correct rights
|
||||||
@ -50,6 +48,8 @@ const isAuthorized: AuthChecker<any> = async ({ context }, rights) => {
|
|||||||
throw new Error('401 Unauthorized')
|
throw new Error('401 Unauthorized')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set new header token
|
||||||
|
context.setHeaders.push({ key: 'token', value: encode(decoded.pubKey) })
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
|
||||||
import { testEnvironment, resetEntities, createUser } from '@test/helpers'
|
import { testEnvironment, createUser, headerPushMock, cleanDB, resetToken } from '@test/helpers'
|
||||||
import { createUserMutation, setPasswordMutation } from '@test/graphql'
|
import { createUserMutation, setPasswordMutation } from '@test/graphql'
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { resetDB } from '@dbTools/helpers'
|
|
||||||
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
||||||
import { User } from '@entity/User'
|
import { User } from '@entity/User'
|
||||||
import CONFIG from '@/config'
|
import CONFIG from '@/config'
|
||||||
@ -30,29 +29,36 @@ jest.mock('@/apis/KlicktippController', () => {
|
|||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let token: string
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const headerPushMock = jest.fn((t) => (token = t.value))
|
|
||||||
|
|
||||||
const context = {
|
|
||||||
setHeaders: {
|
|
||||||
push: headerPushMock,
|
|
||||||
forEach: jest.fn(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
let mutate: any, query: any, con: any
|
let mutate: any, query: any, con: any
|
||||||
|
|
||||||
|
const loginQuery = gql`
|
||||||
|
query ($email: String!, $password: String!, $publisherId: Int) {
|
||||||
|
login(email: $email, password: $password, publisherId: $publisherId) {
|
||||||
|
email
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
language
|
||||||
|
coinanimation
|
||||||
|
klickTipp {
|
||||||
|
newsletterState
|
||||||
|
}
|
||||||
|
hasElopage
|
||||||
|
publisherId
|
||||||
|
isAdmin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const testEnv = await testEnvironment(context)
|
const testEnv = await testEnvironment()
|
||||||
mutate = testEnv.mutate
|
mutate = testEnv.mutate
|
||||||
query = testEnv.query
|
query = testEnv.query
|
||||||
con = testEnv.con
|
con = testEnv.con
|
||||||
|
await cleanDB()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await resetDB(true)
|
await cleanDB()
|
||||||
await con.close()
|
await con.close()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -75,7 +81,7 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await resetEntities([User, LoginEmailOptIn])
|
await cleanDB()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns success', () => {
|
it('returns success', () => {
|
||||||
@ -213,7 +219,7 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await resetEntities([User, LoginEmailOptIn])
|
await cleanDB()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sets email checked to true', () => {
|
it('sets email checked to true', () => {
|
||||||
@ -256,7 +262,7 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await resetEntities([User, LoginEmailOptIn])
|
await cleanDB()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('throws an error', () => {
|
it('throws an error', () => {
|
||||||
@ -282,7 +288,7 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await resetEntities([User, LoginEmailOptIn])
|
await cleanDB()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('throws an error', () => {
|
it('throws an error', () => {
|
||||||
@ -296,24 +302,6 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('login', () => {
|
describe('login', () => {
|
||||||
const loginQuery = gql`
|
|
||||||
query ($email: String!, $password: String!, $publisherId: Int) {
|
|
||||||
login(email: $email, password: $password, publisherId: $publisherId) {
|
|
||||||
email
|
|
||||||
firstName
|
|
||||||
lastName
|
|
||||||
language
|
|
||||||
coinanimation
|
|
||||||
klickTipp {
|
|
||||||
newsletterState
|
|
||||||
}
|
|
||||||
hasElopage
|
|
||||||
publisherId
|
|
||||||
isAdmin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const variables = {
|
const variables = {
|
||||||
email: 'peter@lustig.de',
|
email: 'peter@lustig.de',
|
||||||
password: 'Aa12345_',
|
password: 'Aa12345_',
|
||||||
@ -323,7 +311,7 @@ describe('UserResolver', () => {
|
|||||||
let result: User
|
let result: User
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await resetEntities([User, LoginEmailOptIn])
|
await cleanDB()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('no users in database', () => {
|
describe('no users in database', () => {
|
||||||
@ -340,7 +328,7 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('user is in database', () => {
|
describe('user is in database and correct login data', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await createUser(mutate, {
|
await createUser(mutate, {
|
||||||
email: 'peter@lustig.de',
|
email: 'peter@lustig.de',
|
||||||
@ -353,7 +341,7 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await resetEntities([User, LoginEmailOptIn])
|
await cleanDB()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns the user object', () => {
|
it('returns the user object', () => {
|
||||||
@ -382,5 +370,81 @@ describe('UserResolver', () => {
|
|||||||
expect(headerPushMock).toBeCalledWith({ key: 'token', value: expect.any(String) })
|
expect(headerPushMock).toBeCalledWith({ key: 'token', value: expect.any(String) })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('user is in database and wrong password', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await createUser(mutate, {
|
||||||
|
email: 'peter@lustig.de',
|
||||||
|
firstName: 'Peter',
|
||||||
|
lastName: 'Lustig',
|
||||||
|
language: 'de',
|
||||||
|
publisherId: 1234,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await cleanDB()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns an error', () => {
|
||||||
|
expect(
|
||||||
|
query({ query: loginQuery, variables: { ...variables, password: 'wrong' } }),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('No user with this credentials')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('logout', () => {
|
||||||
|
const logoutQuery = gql`
|
||||||
|
query {
|
||||||
|
logout
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
describe('unauthenticated', () => {
|
||||||
|
it('throws an error', async () => {
|
||||||
|
resetToken()
|
||||||
|
await expect(query({ query: logoutQuery })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('authenticated', () => {
|
||||||
|
const variables = {
|
||||||
|
email: 'peter@lustig.de',
|
||||||
|
password: 'Aa12345_',
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await createUser(mutate, {
|
||||||
|
email: 'peter@lustig.de',
|
||||||
|
firstName: 'Peter',
|
||||||
|
lastName: 'Lustig',
|
||||||
|
language: 'de',
|
||||||
|
publisherId: 1234,
|
||||||
|
})
|
||||||
|
await query({ query: loginQuery, variables })
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await cleanDB()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns true', async () => {
|
||||||
|
await expect(query({ query: logoutQuery })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: { logout: 'true' },
|
||||||
|
errors: undefined,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -373,6 +373,8 @@ export class UserResolver {
|
|||||||
/{code}/g,
|
/{code}/g,
|
||||||
emailOptIn.verificationCode.toString(),
|
emailOptIn.verificationCode.toString(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const emailSent = await sendAccountActivationEmail({
|
const emailSent = await sendAccountActivationEmail({
|
||||||
link: activationLink,
|
link: activationLink,
|
||||||
firstName,
|
firstName,
|
||||||
@ -380,11 +382,13 @@ export class UserResolver {
|
|||||||
email,
|
email,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/* uncomment this, when you need the activation link on the console
|
||||||
// In case EMails are disabled log the activation link for the user
|
// In case EMails are disabled log the activation link for the user
|
||||||
if (!emailSent) {
|
if (!emailSent) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(`Account confirmation link: ${activationLink}`)
|
console.log(`Account confirmation link: ${activationLink}`)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
await queryRunner.commitTransaction()
|
await queryRunner.commitTransaction()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await queryRunner.rollbackTransaction()
|
await queryRunner.rollbackTransaction()
|
||||||
@ -414,6 +418,7 @@ export class UserResolver {
|
|||||||
emailOptIn.verificationCode.toString(),
|
emailOptIn.verificationCode.toString(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const emailSent = await sendAccountActivationEmail({
|
const emailSent = await sendAccountActivationEmail({
|
||||||
link: activationLink,
|
link: activationLink,
|
||||||
firstName: user.firstName,
|
firstName: user.firstName,
|
||||||
@ -421,11 +426,13 @@ export class UserResolver {
|
|||||||
email,
|
email,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/* uncomment this, when you need the activation link on the console
|
||||||
// In case EMails are disabled log the activation link for the user
|
// In case EMails are disabled log the activation link for the user
|
||||||
if (!emailSent) {
|
if (!emailSent) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(`Account confirmation link: ${activationLink}`)
|
console.log(`Account confirmation link: ${activationLink}`)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
await queryRunner.commitTransaction()
|
await queryRunner.commitTransaction()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await queryRunner.rollbackTransaction()
|
await queryRunner.rollbackTransaction()
|
||||||
@ -450,6 +457,7 @@ export class UserResolver {
|
|||||||
optInCode.verificationCode.toString(),
|
optInCode.verificationCode.toString(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const emailSent = await sendResetPasswordEmail({
|
const emailSent = await sendResetPasswordEmail({
|
||||||
link,
|
link,
|
||||||
firstName: user.firstName,
|
firstName: user.firstName,
|
||||||
@ -457,11 +465,13 @@ export class UserResolver {
|
|||||||
email,
|
email,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/* uncomment this, when you need the activation link on the console
|
||||||
// In case EMails are disabled log the activation link for the user
|
// In case EMails are disabled log the activation link for the user
|
||||||
if (!emailSent) {
|
if (!emailSent) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(`Reset password link: ${link}`)
|
console.log(`Reset password link: ${link}`)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -551,7 +561,9 @@ export class UserResolver {
|
|||||||
} catch {
|
} catch {
|
||||||
// TODO is this a problem?
|
// TODO is this a problem?
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
/* uncomment this, when you need the activation link on the console
|
||||||
console.log('Could not subscribe to klicktipp')
|
console.log('Could not subscribe to klicktipp')
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,44 +3,62 @@
|
|||||||
|
|
||||||
import { createTestClient } from 'apollo-server-testing'
|
import { createTestClient } from 'apollo-server-testing'
|
||||||
import createServer from '../src/server/createServer'
|
import createServer from '../src/server/createServer'
|
||||||
import { resetDB, initialize } from '@dbTools/helpers'
|
import { initialize } from '@dbTools/helpers'
|
||||||
import { createUserMutation, setPasswordMutation } from './graphql'
|
import { createUserMutation, setPasswordMutation } from './graphql'
|
||||||
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
||||||
import { User } from '@entity/User'
|
import { User } from '@entity/User'
|
||||||
|
import { entities } from '@entity/index'
|
||||||
|
|
||||||
export const testEnvironment = async (context: any) => {
|
export const headerPushMock = jest.fn((t) => {
|
||||||
|
context.token = t.value
|
||||||
|
})
|
||||||
|
|
||||||
|
const context = {
|
||||||
|
token: '',
|
||||||
|
setHeaders: {
|
||||||
|
push: headerPushMock,
|
||||||
|
forEach: jest.fn(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cleanDB = async () => {
|
||||||
|
// this only works as lond we do not have foreign key constraints
|
||||||
|
for (let i = 0; i < entities.length; i++) {
|
||||||
|
await resetEntity(entities[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const testEnvironment = async () => {
|
||||||
const server = await createServer(context)
|
const server = await createServer(context)
|
||||||
const con = server.con
|
const con = server.con
|
||||||
const testClient = createTestClient(server.apollo)
|
const testClient = createTestClient(server.apollo)
|
||||||
const mutate = testClient.mutate
|
const mutate = testClient.mutate
|
||||||
const query = testClient.query
|
const query = testClient.query
|
||||||
await initialize()
|
await initialize()
|
||||||
await resetDB()
|
|
||||||
return { mutate, query, con }
|
return { mutate, query, con }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const resetEntity = async (entity: any) => {
|
export const resetEntity = async (entity: any) => {
|
||||||
const items = await entity.find()
|
const items = await entity.find({ withDeleted: true })
|
||||||
if (items.length > 0) {
|
if (items.length > 0) {
|
||||||
const ids = items.map((i: any) => i.id)
|
const ids = items.map((i: any) => i.id)
|
||||||
await entity.delete(ids)
|
await entity.delete(ids)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const resetEntities = async (entities: any[]) => {
|
|
||||||
for (let i = 0; i < entities.length; i++) {
|
|
||||||
await resetEntity(entities[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createUser = async (mutate: any, user: any) => {
|
export const createUser = async (mutate: any, user: any) => {
|
||||||
|
// resetToken()
|
||||||
await mutate({ mutation: createUserMutation, variables: user })
|
await mutate({ mutation: createUserMutation, variables: user })
|
||||||
const dbUser = await User.findOne({ where: { email: user.email } })
|
const dbUser = await User.findOne({ where: { email: user.email } })
|
||||||
if (!dbUser) throw new Error('Ups, no user found')
|
if (!dbUser) throw new Error('Ups, no user found')
|
||||||
const optin = await LoginEmailOptIn.findOne(dbUser.id)
|
const optin = await LoginEmailOptIn.findOne({ where: { userId: dbUser.id } })
|
||||||
if (!optin) throw new Error('Ups, no optin found')
|
if (!optin) throw new Error('Ups, no optin found')
|
||||||
await mutate({
|
await mutate({
|
||||||
mutation: setPasswordMutation,
|
mutation: setPasswordMutation,
|
||||||
variables: { password: 'Aa12345_', code: optin.verificationCode },
|
variables: { password: 'Aa12345_', code: optin.verificationCode },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const resetToken = () => {
|
||||||
|
context.token = ''
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
$GRADIDO_LOG_PATH/* {
|
$GRADIDO_LOG_PATH/*.log {
|
||||||
weekly
|
weekly
|
||||||
rotate 26
|
rotate 26
|
||||||
size 10M
|
size 10M
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
Gradido is currently updating...<br>
|
<pre>
|
||||||
please stand by and try again in some minutes<br>
|
Gradido is currently updating...
|
||||||
<br>
|
please stand by and try again in some minutes
|
||||||
|
|
||||||
|
|||||||
@ -42,30 +42,38 @@ if [ -f $LOCK_FILE ] ; then
|
|||||||
fi
|
fi
|
||||||
touch $LOCK_FILE
|
touch $LOCK_FILE
|
||||||
|
|
||||||
|
# find today string
|
||||||
|
TODAY=$(date +"%Y-%m-%d")
|
||||||
|
|
||||||
# Create a new updating.html from the template
|
# Create a new updating.html from the template
|
||||||
\cp $SCRIPT_DIR/nginx/update-page/updating.html.template $UPDATE_HTML
|
\cp $SCRIPT_DIR/nginx/update-page/updating.html.template $UPDATE_HTML
|
||||||
|
|
||||||
|
# redirect all output of the script to the UPDATE_HTML and also have things on console
|
||||||
|
# TODO: this might pose a security risk
|
||||||
|
exec > >(tee -a $UPDATE_HTML) 2>&1
|
||||||
|
|
||||||
# configure nginx for the update-page
|
# configure nginx for the update-page
|
||||||
echo 'Configuring nginx to serve the update-page<br>' >> $UPDATE_HTML
|
echo 'Configuring nginx to serve the update-page' >> $UPDATE_HTML
|
||||||
rm /etc/nginx/sites-enabled/gradido.conf
|
rm /etc/nginx/sites-enabled/gradido.conf
|
||||||
ln -s /etc/nginx/sites-available/update-page.conf /etc/nginx/sites-enabled/
|
ln -s /etc/nginx/sites-available/update-page.conf /etc/nginx/sites-enabled/
|
||||||
sudo /etc/init.d/nginx restart
|
sudo /etc/init.d/nginx restart
|
||||||
|
|
||||||
# stop all services
|
# stop all services
|
||||||
echo 'Stopping all Gradido services<br>' >> $UPDATE_HTML
|
echo 'Stopping all Gradido services' >> $UPDATE_HTML
|
||||||
pm2 stop all
|
pm2 stop all
|
||||||
|
|
||||||
# git
|
# git
|
||||||
BRANCH=${1:-master}
|
BRANCH=${1:-master}
|
||||||
echo "Starting with git pull - branch:$BRANCH<br>" >> $UPDATE_HTML
|
echo "Starting with git pull - branch:$BRANCH" >> $UPDATE_HTML
|
||||||
cd $PROJECT_ROOT
|
cd $PROJECT_ROOT
|
||||||
git fetch origin $BRANCH
|
# TODO: this overfetches alot, but ensures we can use start.sh with tags
|
||||||
|
git fetch origin --all
|
||||||
git checkout $BRANCH
|
git checkout $BRANCH
|
||||||
git pull
|
git pull
|
||||||
export BUILD_COMMIT="$(git rev-parse HEAD)"
|
export BUILD_COMMIT="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
# Generate gradido.conf from template
|
# Generate gradido.conf from template
|
||||||
echo 'Generate new gradido nginx config<br>' >> $UPDATE_HTML
|
echo 'Generate new gradido nginx config' >> $UPDATE_HTML
|
||||||
case "$NGINX_SSL" in
|
case "$NGINX_SSL" in
|
||||||
true) TEMPLATE_FILE="gradido.conf.ssl.template" ;;
|
true) TEMPLATE_FILE="gradido.conf.ssl.template" ;;
|
||||||
*) TEMPLATE_FILE="gradido.conf.template" ;;
|
*) TEMPLATE_FILE="gradido.conf.template" ;;
|
||||||
@ -73,7 +81,7 @@ esac
|
|||||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/gradido.conf
|
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/gradido.conf
|
||||||
|
|
||||||
# Generate update-page.conf from template
|
# Generate update-page.conf from template
|
||||||
echo 'Generate new update-page nginx config<br>' >> $UPDATE_HTML
|
echo 'Generate new update-page nginx config' >> $UPDATE_HTML
|
||||||
case "$NGINX_SSL" in
|
case "$NGINX_SSL" in
|
||||||
true) TEMPLATE_FILE="update-page.conf.ssl.template" ;;
|
true) TEMPLATE_FILE="update-page.conf.ssl.template" ;;
|
||||||
*) TEMPLATE_FILE="update-page.conf.template" ;;
|
*) TEMPLATE_FILE="update-page.conf.template" ;;
|
||||||
@ -91,7 +99,7 @@ envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env
|
|||||||
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env
|
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env
|
||||||
|
|
||||||
# Install & build database
|
# Install & build database
|
||||||
echo 'Updating database<br>' >> $UPDATE_HTML
|
echo 'Updating database' >> $UPDATE_HTML
|
||||||
cd $PROJECT_ROOT/database
|
cd $PROJECT_ROOT/database
|
||||||
yarn install
|
yarn install
|
||||||
yarn build
|
yarn build
|
||||||
@ -104,7 +112,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Install & build backend
|
# Install & build backend
|
||||||
echo 'Updating backend<br>' >> $UPDATE_HTML
|
echo 'Updating backend' >> $UPDATE_HTML
|
||||||
cd $PROJECT_ROOT/backend
|
cd $PROJECT_ROOT/backend
|
||||||
# TODO maybe handle this differently?
|
# TODO maybe handle this differently?
|
||||||
unset NODE_ENV
|
unset NODE_ENV
|
||||||
@ -113,11 +121,11 @@ yarn build
|
|||||||
# TODO maybe handle this differently?
|
# TODO maybe handle this differently?
|
||||||
export NODE_ENV=production
|
export NODE_ENV=production
|
||||||
pm2 delete gradido-backend
|
pm2 delete gradido-backend
|
||||||
pm2 start --name gradido-backend "yarn --cwd $PROJECT_ROOT/backend start" -l $GRADIDO_LOG_PATH/pm2.backend.log --log-date-format 'DD-MM HH:mm:ss.SSS'
|
pm2 start --name gradido-backend "yarn --cwd $PROJECT_ROOT/backend start" -l $GRADIDO_LOG_PATH/pm2.backend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
||||||
pm2 save
|
pm2 save
|
||||||
|
|
||||||
# Install & build frontend
|
# Install & build frontend
|
||||||
echo 'Updating frontend<br>' >> $UPDATE_HTML
|
echo 'Updating frontend' >> $UPDATE_HTML
|
||||||
cd $PROJECT_ROOT/frontend
|
cd $PROJECT_ROOT/frontend
|
||||||
# TODO maybe handle this differently?
|
# TODO maybe handle this differently?
|
||||||
unset NODE_ENV
|
unset NODE_ENV
|
||||||
@ -126,11 +134,11 @@ yarn build
|
|||||||
# TODO maybe handle this differently?
|
# TODO maybe handle this differently?
|
||||||
export NODE_ENV=production
|
export NODE_ENV=production
|
||||||
pm2 delete gradido-frontend
|
pm2 delete gradido-frontend
|
||||||
pm2 start --name gradido-frontend "yarn --cwd $PROJECT_ROOT/frontend start" -l $GRADIDO_LOG_PATH/pm2.frontend.log --log-date-format 'DD-MM HH:mm:ss.SSS'
|
pm2 start --name gradido-frontend "yarn --cwd $PROJECT_ROOT/frontend start" -l $GRADIDO_LOG_PATH/pm2.frontend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
||||||
pm2 save
|
pm2 save
|
||||||
|
|
||||||
# Install & build admin
|
# Install & build admin
|
||||||
echo 'Updating admin<br>' >> $UPDATE_HTML
|
echo 'Updating admin' >> $UPDATE_HTML
|
||||||
cd $PROJECT_ROOT/admin
|
cd $PROJECT_ROOT/admin
|
||||||
# TODO maybe handle this differently?
|
# TODO maybe handle this differently?
|
||||||
unset NODE_ENV
|
unset NODE_ENV
|
||||||
@ -139,14 +147,17 @@ yarn build
|
|||||||
# TODO maybe handle this differently?
|
# TODO maybe handle this differently?
|
||||||
export NODE_ENV=production
|
export NODE_ENV=production
|
||||||
pm2 delete gradido-admin
|
pm2 delete gradido-admin
|
||||||
pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.log --log-date-format 'DD-MM HH:mm:ss.SSS'
|
pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS'
|
||||||
pm2 save
|
pm2 save
|
||||||
|
|
||||||
# let nginx showing gradido
|
# let nginx showing gradido
|
||||||
echo 'Configuring nginx to serve gradido again<br>' >> $UPDATE_HTML
|
echo 'Configuring nginx to serve gradido again' >> $UPDATE_HTML
|
||||||
ln -s /etc/nginx/sites-available/gradido.conf /etc/nginx/sites-enabled/
|
ln -s /etc/nginx/sites-available/gradido.conf /etc/nginx/sites-enabled/
|
||||||
rm /etc/nginx/sites-enabled/update-page.conf
|
rm /etc/nginx/sites-enabled/update-page.conf
|
||||||
sudo /etc/init.d/nginx restart
|
sudo /etc/init.d/nginx restart
|
||||||
|
|
||||||
|
# keep the update log
|
||||||
|
cat $UPDATE_HTML >> $GRADIDO_LOG_PATH/update.$TODAY.log
|
||||||
|
|
||||||
# release lock
|
# release lock
|
||||||
rm $LOCK_FILE
|
rm $LOCK_FILE
|
||||||
Loading…
x
Reference in New Issue
Block a user