diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 55e28db4b..08ecc0379 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -248,7 +248,7 @@ jobs: ########################################################################## - name: Nginx | Build `production` image run: | - docker build -t "gradido/nginx:latest" -t "gradido/nginx:production" -t "gradido/nginx:${VERSION}" -t "gradido/nginx:${BUILD_VERSION}" -f ./nginx/Dockerfile ./ + docker build -t "gradido/nginx:latest" -t "gradido/nginx:production" -t "gradido/nginx:${VERSION}" -t "gradido/nginx:${BUILD_VERSION}" nginx/ docker save "gradido/nginx" > /tmp/nginx.tar - name: Upload Artifact uses: actions/upload-artifact@v2 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 15a736630..5dbbf685f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -199,7 +199,7 @@ jobs: ########################################################################## - name: nginx | Build `test` image run: | - docker build -t "gradido/nginx:test" -f ./nginx/Dockerfile ./ + docker build -t "gradido/nginx:test" nginx/ docker save "gradido/nginx:test" > /tmp/nginx.tar - name: Upload Artifact uses: actions/upload-artifact@v2 @@ -470,7 +470,7 @@ jobs: report_name: Coverage Admin Interface type: lcov result_path: ./coverage/lcov.info - min_coverage: 76 + min_coverage: 77 token: ${{ github.token }} ############################################################################## @@ -520,7 +520,7 @@ jobs: report_name: Coverage Backend type: lcov result_path: ./backend/coverage/lcov.info - min_coverage: 40 + min_coverage: 45 token: ${{ github.token }} ############################################################################## diff --git a/.gitignore b/.gitignore index 5682953d4..b02b9d6ec 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,9 @@ nbproject .metadata /.env package-lock.json +/deployment/bare_metal/.env +/deployment/bare_metal/nginx/sites-available/gradido.conf +/deployment/bare_metal/nginx/sites-available/update-page.conf +/deployment/bare_metal/nginx/update-page/updating.html +/deployment/bare_metal/log +/deployment/bare_metal/backup diff --git a/README.md b/README.md index ce8e84df0..355a40b82 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ We are currently restructuring the service to reduce dependencies and unify busi ### Open the wallet -Once you have `docker-compose` up and running, you can open [http://localhost/vue](http://localhost/vue) and create yourself a new wallet account. +Once you have `docker-compose` up and running, you can open [http://localhost/](http://localhost/) and create yourself a new wallet account. ## How to release @@ -90,7 +90,7 @@ Note: The Changelog will be regenerated with all tags on release on the external | Problem | Issue | Solution | Description | | ------- | ----- | -------- | ----------- | | docker-compose raises database connection errors | [#1062](https://github.com/gradido/gradido/issues/1062) | End `ctrl+c` and restart the `docker-compose up` after a successful build | Several Database connection related errors occur in the docker-compose log. | -| Wallet page is empty | [#1063](https://github.com/gradido/gradido/issues/1063) | Accept Cookies and Local Storage in your Browser | The page stays empty when navigating to [http://localhost/vue](http://localhost/vue) | +| Wallet page is empty | [#1063](https://github.com/gradido/gradido/issues/1063) | Accept Cookies and Local Storage in your Browser | The page stays empty when navigating to [http://localhost/](http://localhost/) | ## Useful Links diff --git a/admin/.env.dist b/admin/.env.dist index 6d78e6782..66c84dda8 100644 --- a/admin/.env.dist +++ b/admin/.env.dist @@ -1,3 +1,4 @@ GRAPHQL_URI=http://localhost:4000/graphql -WALLET_AUTH_URL=http://localhost/vue/authenticate?token=$1 +WALLET_AUTH_URL=http://localhost/authenticate?token={token} +WALLET_URL=http://localhost/login DEBUG_DISABLE_AUTH=false \ No newline at end of file diff --git a/admin/.env.template b/admin/.env.template new file mode 100644 index 000000000..a965b1bb1 --- /dev/null +++ b/admin/.env.template @@ -0,0 +1,4 @@ +GRAPHQL_URI=$GRAPHQL_URI +WALLET_AUTH_URL=$WALLET_AUTH_URL +WALLET_URL=$WALLET_URL +DEBUG_DISABLE_AUTH=false \ No newline at end of file diff --git a/admin/package.json b/admin/package.json index c94d0a2b0..93fbed8ae 100644 --- a/admin/package.json +++ b/admin/package.json @@ -33,6 +33,7 @@ "core-js": "^3.6.5", "dotenv-webpack": "^7.0.3", "graphql": "^15.6.1", + "express": "^4.17.1", "identity-obj-proxy": "^3.0.0", "jest": "26.6.3", "moment": "^2.29.1", diff --git a/admin/run/server.js b/admin/run/server.js index 97a525427..bccefc65c 100644 --- a/admin/run/server.js +++ b/admin/run/server.js @@ -1,15 +1,21 @@ // Imports const express = require('express') -const serveStatic = require('serve-static') +const path = require('path') -// Port +// Host & Port +const hostname = '127.0.0.1' const port = process.env.PORT || 8080 // Express Server const app = express() -// eslint-disable-next-line node/no-path-concat -app.use(serveStatic(__dirname + '/../dist')) -app.listen(port) +// Serve files +app.use(express.static(path.join(__dirname, '../dist'))) +// Default to index.html +app.get('*', (req, res) => { + res.sendFile(path.join(__dirname, '../dist/index.html')) +}) -// eslint-disable-next-line no-console -console.log(`http://admin:${port} server started.`) +app.listen(port, hostname, () => { + // eslint-disable-next-line no-console + console.log('Listening at http://%s:%s/', hostname, port) +}) diff --git a/admin/src/components/ConfirmRegisterMailFormular.spec.js b/admin/src/components/ConfirmRegisterMailFormular.spec.js index 705a185a3..78f5791dc 100644 --- a/admin/src/components/ConfirmRegisterMailFormular.spec.js +++ b/admin/src/components/ConfirmRegisterMailFormular.spec.js @@ -19,6 +19,7 @@ const mocks = { } const propsData = { + checked: false, email: 'bob@baumeister.de', dateLastSend: '', } diff --git a/admin/src/components/ConfirmRegisterMailFormular.vue b/admin/src/components/ConfirmRegisterMailFormular.vue index 5052a8a3e..635b80939 100644 --- a/admin/src/components/ConfirmRegisterMailFormular.vue +++ b/admin/src/components/ConfirmRegisterMailFormular.vue @@ -1,19 +1,20 @@ @@ -23,6 +24,9 @@ import { sendActivationEmail } from '../graphql/sendActivationEmail' export default { name: 'ConfirmRegisterMail', props: { + checked: { + type: Boolean, + }, email: { type: String, }, diff --git a/admin/src/components/CreationTransactionListFormular.spec.js b/admin/src/components/CreationTransactionListFormular.spec.js index 9817d6b8f..32dcb6c9d 100644 --- a/admin/src/components/CreationTransactionListFormular.spec.js +++ b/admin/src/components/CreationTransactionListFormular.spec.js @@ -8,7 +8,7 @@ const apolloQueryMock = jest.fn().mockResolvedValue({ transactionList: { transactions: [ { - type: 'created', + type: 'creation', balance: 100, decayStart: 0, decayEnd: 0, @@ -27,7 +27,7 @@ const apolloQueryMock = jest.fn().mockResolvedValue({ }, }, { - type: 'created', + type: 'creation', balance: 200, decayStart: 0, decayEnd: 0, @@ -58,9 +58,7 @@ const mocks = { query: apolloQueryMock, }, $toasted: { - global: { - error: toastedErrorMock, - }, + error: toastedErrorMock, }, } diff --git a/admin/src/components/CreationTransactionListFormular.vue b/admin/src/components/CreationTransactionListFormular.vue index 09e1fa92a..7fed4adcc 100644 --- a/admin/src/components/CreationTransactionListFormular.vue +++ b/admin/src/components/CreationTransactionListFormular.vue @@ -30,10 +30,10 @@ export default { }, }) .then((result) => { - this.items = result.data.transactionList.transactions + this.items = result.data.transactionList.transactions.filter((t) => t.type === 'creation') }) .catch((error) => { - this.$toasted.global.error(error.message) + this.$toasted.error(error.message) }) }, }, diff --git a/admin/src/components/NavBar.spec.js b/admin/src/components/NavBar.spec.js index 6871cb4f7..b084dd18b 100644 --- a/admin/src/components/NavBar.spec.js +++ b/admin/src/components/NavBar.spec.js @@ -53,13 +53,17 @@ describe('NavBar', () => { }) describe('logout', () => { - // const assignLocationSpy = jest.fn() + const windowLocationMock = jest.fn() beforeEach(async () => { + delete window.location + window.location = { + assign: windowLocationMock, + } await wrapper.findAll('a').at(6).trigger('click') }) it('redirects to /logout', () => { - expect(routerPushMock).toBeCalledWith('/logout') + expect(windowLocationMock).toBeCalledWith('http://localhost/login') }) it('dispatches logout to store', () => { diff --git a/admin/src/components/NavBar.vue b/admin/src/components/NavBar.vue index 03ace0335..0e8ad8acf 100644 --- a/admin/src/components/NavBar.vue +++ b/admin/src/components/NavBar.vue @@ -33,11 +33,12 @@ export default { name: 'navbar', methods: { logout() { + window.location.assign(CONFIG.WALLET_URL) + // window.location = CONFIG.WALLET_URL this.$store.dispatch('logout') - this.$router.push('/logout') }, wallet() { - window.location = CONFIG.WALLET_AUTH_URL.replace('$1', this.$store.state.token) + window.location = CONFIG.WALLET_AUTH_URL.replace('{token}', this.$store.state.token) this.$store.dispatch('logout') // logout without redirect }, }, diff --git a/admin/src/components/UserTable.spec.js b/admin/src/components/UserTable.spec.js index e25f53015..e26a548cc 100644 --- a/admin/src/components/UserTable.spec.js +++ b/admin/src/components/UserTable.spec.js @@ -3,31 +3,287 @@ import UserTable from './UserTable.vue' const localVue = global.localVue +const apolloQueryMock = jest.fn() +apolloQueryMock.mockResolvedValue() + describe('UserTable', () => { let wrapper - const propsData = { - type: 'Type', - itemsUser: [], - fieldsTable: [], - creation: [], + const defaultItemsUser = [ + { + email: 'bibi@bloxberg.de', + firstName: 'Bibi', + lastName: 'Bloxberg', + creation: [1000, 1000, 1000], + }, + { + email: 'bibi@bloxberg.de', + firstName: 'Bibi', + lastName: 'Bloxberg', + creation: [1000, 1000, 1000], + }, + { + email: 'bibi@bloxberg.de', + firstName: 'Bibi', + lastName: 'Bloxberg', + creation: [1000, 1000, 1000], + }, + ] + + const confirmationItemsUser = [ + { + email: 'bibi@bloxberg.de', + firstName: 'Bibi', + lastName: 'Bloxberg', + amount: 10, + memo: 'Test 1', + date: '11-09-2001', + moderator: 1, + }, + { + email: 'bibi@bloxberg.de', + firstName: 'Bibi', + lastName: 'Bloxberg', + amount: 10, + memo: 'Test 2', + date: '21-09-2001', + moderator: 1, + }, + { + email: 'bibi@bloxberg.de', + firstName: 'Bibi', + lastName: 'Bloxberg', + amount: 10, + memo: 'Test 3', + date: '30-09-2001', + moderator: 1, + }, + ] + + const propsDataPageUserSearch = { + type: 'PageUserSearch', + itemsUser: defaultItemsUser, + fieldsTable: [ + 'email', + 'firstName', + 'lastName', + 'creation', + 'show_details', + 'confirm_mail', + 'transactions_list', + ], + } + + const propsDataUserListSearch = { + type: 'UserListSearch', + itemsUser: defaultItemsUser, + fieldsTable: ['bookmark', 'email', 'firstName', 'lastName', 'creation'], + creation: [1000, 1000, 1000], + } + + const propsDataUserListMassCreation = { + type: 'UserListMassCreation', + itemsUser: defaultItemsUser, + fieldsTable: ['email', 'firstName', 'lastName', 'creation', 'bookmark'], + creation: [1000, 1000, 1000], + } + + const propsDataPageCreationConfirm = { + type: 'PageCreationConfirm', + itemsUser: confirmationItemsUser, + fieldsTable: [ + 'bookmark', + 'email', + 'firstName', + 'lastName', + 'amount', + 'memo', + 'date', + 'moderator', + 'edit_creation', + 'confirm', + ], } const mocks = { $t: jest.fn((t) => t), + $moment: jest.fn(() => { + return { + format: jest.fn((m) => m), + subtract: jest.fn(() => { + return { + format: jest.fn((m) => m), + } + }), + } + }), + $apollo: { + query: apolloQueryMock, + }, + $store: { + commit: jest.fn(), + }, } - const Wrapper = () => { + const Wrapper = (propsData) => { return mount(UserTable, { localVue, propsData, mocks }) } describe('mount', () => { - beforeEach(() => { - wrapper = Wrapper() + describe('type PageUserSearch', () => { + beforeEach(() => { + wrapper = Wrapper(propsDataPageUserSearch) + }) + + it('has a DIV element with the class.component-user-table', () => { + expect(wrapper.find('.component-user-table').exists()).toBeTruthy() + }) + + it('has a DIV element with the id overlay that is not displayed', () => { + expect(wrapper.find('#overlay').exists()).toBeTruthy() + expect(wrapper.find('#overlay').attributes('style')).toBe('display: none;') + }) + + describe('table', () => { + it('has a table', () => { + expect(wrapper.find('table').exists()).toBeTruthy() + }) + + describe('header definition', () => { + it('has 4 column', () => { + expect(wrapper.findAll('th').length).toBe(7) + }) + + it('has Email as first column', () => { + expect(wrapper.find('th[aria-colindex="1"] div').text()).toBe('Email') + }) + + it('has First Name as second column', () => { + expect(wrapper.find('th[aria-colindex="2"] div').text()).toBe('First Name') + }) + + it('has Last Name as third column', () => { + expect(wrapper.find('th[aria-colindex="3"] div').text()).toBe('Last Name') + }) + + it('has Creation as fourth column', () => { + expect(wrapper.find('th[aria-colindex="4"] div').text()).toBe('Creation') + }) + + it('has Creation as fifth column', () => { + expect(wrapper.find('th[aria-colindex="5"] div').text()).toBe('Show Details') + }) + + it('has Creation as sixth column', () => { + expect(wrapper.find('th[aria-colindex="6"] div').text()).toBe('Confirm Mail') + }) + + it('has Creation as seventh column', () => { + expect(wrapper.find('th[aria-colindex="7"] div').text()).toBe('Transactions List') + }) + }) + + describe('content', () => { + it('has 3 rows', () => { + expect(wrapper.findAll('tbody tr').length).toBe(3) + }) + + it('has 7 columns', () => { + expect(wrapper.findAll('tr:nth-child(1) > td').length).toBe(7) + }) + + it('click button on fifth column', () => { + wrapper.find('tbody tr td[aria-colindex="5"] button').trigger('click') + }) + }) + }) + + // it('expect(wrapper.html()).', () => { + // // eslint-disable-next-line no-console + // console.log(wrapper.html()) + // }) }) - it('has a DIV element with the class.component-user-table', () => { - expect(wrapper.find('.component-user-table').exists()).toBeTruthy() + describe('type UserListSearch', () => { + beforeEach(() => { + wrapper = Wrapper(propsDataUserListSearch) + }) + + it('has a DIV element with the class.component-user-table', () => { + expect(wrapper.find('.component-user-table').exists()).toBeTruthy() + }) + + // it('expect(wrapper.html()).', () => { + // // eslint-disable-next-line no-console + // console.log(wrapper.html()) + // }) }) + + describe('type UserListMassCreation', () => { + beforeEach(() => { + wrapper = Wrapper(propsDataUserListMassCreation) + }) + + it('has a DIV element with the class.component-user-table', () => { + expect(wrapper.find('.component-user-table').exists()).toBeTruthy() + }) + + // it('expect(wrapper.html()).', () => { + // // eslint-disable-next-line no-console + // console.log(wrapper.html()) + // }) + }) + + describe('type PageCreationConfirm', () => { + beforeEach(() => { + wrapper = Wrapper(propsDataPageCreationConfirm) + }) + + it('has a DIV element with the class.component-user-table', () => { + expect(wrapper.find('.component-user-table').exists()).toBeTruthy() + }) + + // it('expect(wrapper.html()).', () => { + // // eslint-disable-next-line no-console + // console.log(wrapper.html()) + // }) + }) + /** + + + + + + + + */ }) }) diff --git a/admin/src/components/UserTable.vue b/admin/src/components/UserTable.vue index 3f5393412..3f8dface3 100644 --- a/admin/src/components/UserTable.vue +++ b/admin/src/components/UserTable.vue @@ -74,6 +74,7 @@