diff --git a/admin/package.json b/admin/package.json index 3406c326a..521f34bfc 100644 --- a/admin/package.json +++ b/admin/package.json @@ -33,6 +33,7 @@ "bootstrap": "4.3.1", "bootstrap-vue": "^2.21.2", "core-js": "^3.6.5", + "date-fns": "^2.29.3", "dotenv-webpack": "^7.0.3", "express": "^4.17.1", "graphql": "^15.6.1", diff --git a/admin/src/components/Fedaration/FederationVisualizeItem.spec.js b/admin/src/components/Fedaration/FederationVisualizeItem.spec.js new file mode 100644 index 000000000..6058cc6f4 --- /dev/null +++ b/admin/src/components/Fedaration/FederationVisualizeItem.spec.js @@ -0,0 +1,183 @@ +import { mount } from '@vue/test-utils' +import FederationVisualizeItem from './FederationVisualizeItem.vue' + +const localVue = global.localVue +const today = new Date() +const createdDate = new Date() +createdDate.setDate(createdDate.getDate() - 3) + +let propsData = { + item: { + id: 7590, + foreign: false, + publicKey: 'eaf6a426b24fd54f8fbae11c17700fc595080ca25159579c63d38dbc64284ba7', + url: 'http://localhost/api/2_0', + lastAnnouncedAt: createdDate, + verifiedAt: today, + lastErrorAt: null, + createdAt: createdDate, + updatedAt: null, + }, +} + +const mocks = { + $i18n: { + locale: 'en', + }, +} + +describe('FederationVisualizeItem', () => { + let wrapper + + const Wrapper = () => { + return mount(FederationVisualizeItem, { localVue, mocks, propsData }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('renders the component', () => { + expect(wrapper.find('div.federation-visualize-item').exists()).toBe(true) + }) + + describe('rendering item properties', () => { + it('has the url', () => { + expect(wrapper.find('.row > div:nth-child(2) > div').text()).toBe( + 'http://localhost/api/2_0', + ) + }) + + it('has the public key', () => { + expect(wrapper.find('.row > div:nth-child(2) > small').text()).toContain( + 'eaf6a426b24fd54f8fbae11c17700fc595080ca25159579c63d38dbc64284ba7'.substring(0, 26), + ) + }) + + describe('verified item', () => { + it('has the check icon', () => { + expect(wrapper.find('svg.bi-check').exists()).toBe(true) + }) + + it('has the text variant "success"', () => { + expect(wrapper.find('.text-success').exists()).toBe(true) + }) + }) + + describe('not verified item', () => { + beforeEach(() => { + propsData = { + item: { + id: 7590, + foreign: false, + publicKey: 'eaf6a426b24fd54f8fbae11c17700fc595080ca25159579c63d38dbc64284ba7', + url: 'http://localhost/api/2_0', + lastAnnouncedAt: createdDate, + verifiedAt: null, + lastErrorAt: null, + createdAt: createdDate, + updatedAt: null, + }, + } + wrapper = Wrapper() + }) + + it('has the x-circle icon', () => { + expect(wrapper.find('svg.bi-x-circle').exists()).toBe(true) + }) + + it('has the text variant "danger"', () => { + expect(wrapper.find('.text-danger').exists()).toBe(true) + }) + }) + + // describe('with different locales (de, en, fr, es, nl)', () => { + describe('lastAnnouncedAt', () => { + it('computes the time string for different locales (de, en, fr, es, nl)', () => { + wrapper.vm.$i18n.locale = 'de' + wrapper = Wrapper() + expect(wrapper.vm.lastAnnouncedAt).toBe('vor 3 Tagen') + + wrapper.vm.$i18n.locale = 'fr' + wrapper = Wrapper() + expect(wrapper.vm.lastAnnouncedAt).toBe('il y a 3 jours') + + wrapper.vm.$i18n.locale = 'es' + wrapper = Wrapper() + expect(wrapper.vm.lastAnnouncedAt).toBe('hace 3 días') + + wrapper.vm.$i18n.locale = 'nl' + wrapper = Wrapper() + expect(wrapper.vm.lastAnnouncedAt).toBe('3 dagen geleden') + }) + + describe('lastAnnouncedAt == null', () => { + beforeEach(() => { + propsData = { + item: { + id: 7590, + foreign: false, + publicKey: 'eaf6a426b24fd54f8fbae11c17700fc595080ca25159579c63d38dbc64284ba7', + url: 'http://localhost/api/2_0', + lastAnnouncedAt: null, + verifiedAt: null, + lastErrorAt: null, + createdAt: createdDate, + updatedAt: null, + }, + } + wrapper = Wrapper() + }) + + it('computes empty string', async () => { + expect(wrapper.vm.lastAnnouncedAt).toBe('') + }) + }) + }) + + describe('createdAt', () => { + it('computes the time string for different locales (de, en, fr, es, nl)', () => { + wrapper.vm.$i18n.locale = 'de' + wrapper = Wrapper() + expect(wrapper.vm.createdAt).toBe('vor 3 Tagen') + + wrapper.vm.$i18n.locale = 'fr' + wrapper = Wrapper() + expect(wrapper.vm.createdAt).toBe('il y a 3 jours') + + wrapper.vm.$i18n.locale = 'es' + wrapper = Wrapper() + expect(wrapper.vm.createdAt).toBe('hace 3 días') + + wrapper.vm.$i18n.locale = 'nl' + wrapper = Wrapper() + expect(wrapper.vm.createdAt).toBe('3 dagen geleden') + }) + + describe('createdAt == null', () => { + beforeEach(() => { + propsData = { + item: { + id: 7590, + foreign: false, + publicKey: 'eaf6a426b24fd54f8fbae11c17700fc595080ca25159579c63d38dbc64284ba7', + url: 'http://localhost/api/2_0', + lastAnnouncedAt: createdDate, + verifiedAt: null, + lastErrorAt: null, + createdAt: null, + updatedAt: null, + }, + } + wrapper = Wrapper() + }) + + it('computes empty string', async () => { + expect(wrapper.vm.createdAt).toBe('') + }) + }) + }) + }) + }) +}) diff --git a/admin/src/components/Fedaration/FederationVisualizeItem.vue b/admin/src/components/Fedaration/FederationVisualizeItem.vue new file mode 100644 index 000000000..faace7da1 --- /dev/null +++ b/admin/src/components/Fedaration/FederationVisualizeItem.vue @@ -0,0 +1,63 @@ + + + + + + {{ item.url }} + {{ `${item.publicKey.substring(0, 26)}…` }} + + {{ lastAnnouncedAt }} + {{ createdAt }} + + + + diff --git a/admin/src/components/NavBar.spec.js b/admin/src/components/NavBar.spec.js index 1927f258c..6a4a69959 100644 --- a/admin/src/components/NavBar.spec.js +++ b/admin/src/components/NavBar.spec.js @@ -62,8 +62,12 @@ describe('NavBar', () => { ) }) + it('has a link to /federation', () => { + expect(wrapper.findAll('.nav-item').at(3).find('a').attributes('href')).toBe('/federation') + }) + it('has a link to /statistic', () => { - expect(wrapper.findAll('.nav-item').at(3).find('a').attributes('href')).toBe('/statistic') + expect(wrapper.findAll('.nav-item').at(4).find('a').attributes('href')).toBe('/statistic') }) }) @@ -72,7 +76,7 @@ describe('NavBar', () => { beforeEach(async () => { delete window.location window.location = '' - await wrapper.findAll('.nav-item').at(4).find('a').trigger('click') + await wrapper.findAll('.nav-item').at(5).find('a').trigger('click') }) afterEach(() => { @@ -97,7 +101,7 @@ describe('NavBar', () => { window.location = { assign: windowLocationMock, } - await wrapper.findAll('.nav-item').at(5).find('a').trigger('click') + await wrapper.findAll('.nav-item').at(6).find('a').trigger('click') }) afterEach(() => { diff --git a/admin/src/components/NavBar.vue b/admin/src/components/NavBar.vue index dae4bba91..2efeda048 100644 --- a/admin/src/components/NavBar.vue +++ b/admin/src/components/NavBar.vue @@ -1,6 +1,6 @@ - + @@ -19,6 +19,9 @@ {{ $t('navbar.automaticContributions') }} + + {{ $t('navbar.instances') }} + {{ $t('navbar.statistic') }} {{ $t('navbar.my-account') }} {{ $t('navbar.logout') }} diff --git a/admin/src/graphql/getCommunities.js b/admin/src/graphql/getCommunities.js new file mode 100644 index 000000000..ccf894f6b --- /dev/null +++ b/admin/src/graphql/getCommunities.js @@ -0,0 +1,17 @@ +import gql from 'graphql-tag' + +export const getCommunities = gql` + query { + getCommunities { + id + foreign + publicKey + url + lastAnnouncedAt + verifiedAt + lastErrorAt + createdAt + updatedAt + } + } +` diff --git a/admin/src/locales/de.json b/admin/src/locales/de.json index f98dc90f3..e7fb80062 100644 --- a/admin/src/locales/de.json +++ b/admin/src/locales/de.json @@ -68,6 +68,13 @@ "error": "Fehler", "expired": "abgelaufen", "e_mail": "E-Mail", + "federation": { + "createdAt": "Erstellt am", + "gradidoInstances": "Gradido Instanzen", + "lastAnnouncedAt": "letzte Bekanntgabe", + "url": "Url", + "verified": "Verifiziert" + }, "firstname": "Vorname", "footer": { "app_version": "App version {version}", @@ -105,6 +112,7 @@ "name": "Name", "navbar": { "automaticContributions": "Automatische Beiträge", + "instances": "Instanzen", "logout": "Abmelden", "my-account": "Mein Konto", "statistic": "Statistik", diff --git a/admin/src/locales/en.json b/admin/src/locales/en.json index 358c62a15..8ed53cd4b 100644 --- a/admin/src/locales/en.json +++ b/admin/src/locales/en.json @@ -68,6 +68,13 @@ "error": "Error", "expired": "expired", "e_mail": "E-mail", + "federation": { + "createdAt": "Created At ", + "gradidoInstances": "Gradido Instances", + "lastAnnouncedAt": "Last Announced", + "url": "Url", + "verified": "Verified" + }, "firstname": "Firstname", "footer": { "app_version": "App version {version}", @@ -105,6 +112,7 @@ "name": "Name", "navbar": { "automaticContributions": "Automatic Contributions", + "instances": "Instances", "logout": "Logout", "my-account": "My Account", "statistic": "Statistic", diff --git a/admin/src/pages/FederationVisualize.spec.js b/admin/src/pages/FederationVisualize.spec.js new file mode 100644 index 000000000..67d6dffde --- /dev/null +++ b/admin/src/pages/FederationVisualize.spec.js @@ -0,0 +1,125 @@ +import { mount } from '@vue/test-utils' +import FederationVisualize from './FederationVisualize' +import VueApollo from 'vue-apollo' +import { createMockClient } from 'mock-apollo-client' +import { getCommunities } from '@/graphql/getCommunities' +import { toastErrorSpy } from '../../test/testSetup' + +const mockClient = createMockClient() +const apolloProvider = new VueApollo({ + defaultClient: mockClient, +}) + +const localVue = global.localVue + +localVue.use(VueApollo) + +const mocks = { + $t: (key) => key, + $d: jest.fn((d) => d), + $i18n: { + locale: 'en', + t: (key) => key, + }, +} + +const defaultData = () => { + return { + getCommunities: [ + { + id: 1776, + foreign: true, + publicKey: 'c7ca9e742421bb167b8666cb78f90b40c665b8f35db8f001988d44dbb3ce8527', + url: 'http://localhost/api/2_0', + lastAnnouncedAt: '2023-04-07T12:27:24.037Z', + verifiedAt: null, + lastErrorAt: null, + createdAt: '2023-04-07T11:45:06.254Z', + updatedAt: null, + __typename: 'Community', + }, + { + id: 1775, + foreign: true, + publicKey: 'c7ca9e742421bb167b8666cb78f90b40c665b8f35db8f001988d44dbb3ce8527', + url: 'http://localhost/api/1_1', + lastAnnouncedAt: '2023-04-07T12:27:24.023Z', + verifiedAt: null, + lastErrorAt: null, + createdAt: '2023-04-07T11:45:06.234Z', + updatedAt: null, + __typename: 'Community', + }, + { + id: 1774, + foreign: true, + publicKey: 'c7ca9e742421bb167b8666cb78f90b40c665b8f35db8f001988d44dbb3ce8527', + url: 'http://localhost/api/1_0', + lastAnnouncedAt: '2023-04-07T12:27:24.009Z', + verifiedAt: null, + lastErrorAt: null, + createdAt: '2023-04-07T11:45:06.218Z', + updatedAt: null, + __typename: 'Community', + }, + ], + } +} + +describe('FederationVisualize', () => { + let wrapper + const getCommunitiesMock = jest.fn() + + mockClient.setRequestHandler( + getCommunities, + getCommunitiesMock + .mockRejectedValueOnce({ message: 'Ouch!' }) + .mockResolvedValue({ data: defaultData() }), + ) + + const Wrapper = () => { + return mount(FederationVisualize, { localVue, mocks, apolloProvider }) + } + + describe('mount', () => { + beforeEach(() => { + jest.clearAllMocks() + wrapper = Wrapper() + }) + + describe('server error', () => { + it('toast error', () => { + expect(toastErrorSpy).toBeCalledWith('Ouch!') + }) + }) + + describe('sever success', () => { + it('sends query to Apollo when created', () => { + expect(getCommunitiesMock).toBeCalled() + }) + + it('has a DIV element with the class "federation-visualize"', () => { + expect(wrapper.find('div.federation-visualize').exists()).toBe(true) + }) + + it('has a refresh button', () => { + expect(wrapper.find('[data-test="federation-communities-refresh-btn"]').exists()).toBe(true) + }) + + it('renders 3 community list items', () => { + expect(wrapper.findAll('.list-group-item').length).toBe(3) + }) + + describe('cklicking the refresh button', () => { + beforeEach(async () => { + jest.clearAllMocks() + await wrapper.find('[data-test="federation-communities-refresh-btn"]').trigger('click') + }) + + it('calls the API', async () => { + expect(getCommunitiesMock).toBeCalled() + }) + }) + }) + }) +}) diff --git a/admin/src/pages/FederationVisualize.vue b/admin/src/pages/FederationVisualize.vue new file mode 100644 index 000000000..383cf064d --- /dev/null +++ b/admin/src/pages/FederationVisualize.vue @@ -0,0 +1,69 @@ + + + + {{ $t('federation.gradidoInstances') }} + + + + + + + {{ $t('federation.verified') }} + {{ $t('federation.url') }} + {{ $t('federation.lastAnnouncedAt') }} + {{ $t('federation.createdAt') }} + + + + + + + + diff --git a/admin/src/router/router.test.js b/admin/src/router/router.test.js index ad1ad1245..886d4eeab 100644 --- a/admin/src/router/router.test.js +++ b/admin/src/router/router.test.js @@ -45,7 +45,7 @@ describe('router', () => { describe('routes', () => { it('has nine routes defined', () => { - expect(routes).toHaveLength(8) + expect(routes).toHaveLength(9) }) it('has "/overview" as default', async () => { @@ -88,6 +88,13 @@ describe('router', () => { }) }) + describe('federation', () => { + it('loads the "FederationVisualize" page', async () => { + const component = await routes.find((r) => r.path === '/federation').component() + expect(component.default.name).toBe('FederationVisualize') + }) + }) + describe('not found page', () => { it('renders the "NotFound" component', async () => { const component = await routes.find((r) => r.path === '*').component() diff --git a/admin/src/router/routes.js b/admin/src/router/routes.js index b01466cfc..d26fdfd96 100644 --- a/admin/src/router/routes.js +++ b/admin/src/router/routes.js @@ -31,6 +31,10 @@ const routes = [ path: '*', component: () => import('@/components/NotFoundPage.vue'), }, + { + path: '/federation', + component: () => import('@/pages/FederationVisualize.vue'), + }, ] export default routes diff --git a/admin/yarn.lock b/admin/yarn.lock index ee4d635a6..c270b80bf 100644 --- a/admin/yarn.lock +++ b/admin/yarn.lock @@ -5038,6 +5038,11 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +date-fns@^2.29.3: + version "2.29.3" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" + integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== + de-indent@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" diff --git a/backend/src/graphql/model/Community.ts b/backend/src/graphql/model/Community.ts index 22b2b1fc6..d79d40034 100644 --- a/backend/src/graphql/model/Community.ts +++ b/backend/src/graphql/model/Community.ts @@ -8,9 +8,7 @@ export class Community { this.foreign = dbCom.foreign this.publicKey = dbCom.publicKey.toString() this.url = - (dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/') + - 'api/' + - dbCom.apiVersion + (dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/') + dbCom.apiVersion this.lastAnnouncedAt = dbCom.lastAnnouncedAt this.verifiedAt = dbCom.verifiedAt this.lastErrorAt = dbCom.lastErrorAt diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 5b4b26cad..26f4a3390 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -36,6 +36,7 @@ describe('CommunityResolver', () => { let foreignCom1: DbCommunity let foreignCom2: DbCommunity let foreignCom3: DbCommunity + describe('with empty list', () => { it('returns no community entry', async () => { // const result: Community[] = await query({ query: getCommunities }) @@ -56,7 +57,7 @@ describe('CommunityResolver', () => { homeCom1.foreign = false homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity') homeCom1.apiVersion = '1_0' - homeCom1.endPoint = 'http://localhost' + homeCom1.endPoint = 'http://localhost/api' homeCom1.createdAt = new Date() await DbCommunity.insert(homeCom1) @@ -64,7 +65,7 @@ describe('CommunityResolver', () => { homeCom2.foreign = false homeCom2.publicKey = Buffer.from('publicKey-HomeCommunity') homeCom2.apiVersion = '1_1' - homeCom2.endPoint = 'http://localhost' + homeCom2.endPoint = 'http://localhost/api' homeCom2.createdAt = new Date() await DbCommunity.insert(homeCom2) @@ -72,24 +73,24 @@ describe('CommunityResolver', () => { homeCom3.foreign = false homeCom3.publicKey = Buffer.from('publicKey-HomeCommunity') homeCom3.apiVersion = '2_0' - homeCom3.endPoint = 'http://localhost' + homeCom3.endPoint = 'http://localhost/api' homeCom3.createdAt = new Date() await DbCommunity.insert(homeCom3) }) - it('returns three home-community entries', async () => { + it('returns 3 home-community entries', async () => { await expect(query({ query: getCommunities })).resolves.toMatchObject({ data: { getCommunities: [ { - id: 1, - foreign: homeCom1.foreign, + id: 3, + foreign: homeCom3.foreign, publicKey: expect.stringMatching('publicKey-HomeCommunity'), - url: expect.stringMatching('http://localhost/api/1_0'), + url: expect.stringMatching('http://localhost/api/2_0'), lastAnnouncedAt: null, verifiedAt: null, lastErrorAt: null, - createdAt: homeCom1.createdAt.toISOString(), + createdAt: homeCom3.createdAt.toISOString(), updatedAt: null, }, { @@ -104,14 +105,14 @@ describe('CommunityResolver', () => { updatedAt: null, }, { - id: 3, - foreign: homeCom3.foreign, + id: 1, + foreign: homeCom1.foreign, publicKey: expect.stringMatching('publicKey-HomeCommunity'), - url: expect.stringMatching('http://localhost/api/2_0'), + url: expect.stringMatching('http://localhost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, lastErrorAt: null, - createdAt: homeCom3.createdAt.toISOString(), + createdAt: homeCom1.createdAt.toISOString(), updatedAt: null, }, ], @@ -128,7 +129,7 @@ describe('CommunityResolver', () => { foreignCom1.foreign = true foreignCom1.publicKey = Buffer.from('publicKey-ForeignCommunity') foreignCom1.apiVersion = '1_0' - foreignCom1.endPoint = 'http://remotehost' + foreignCom1.endPoint = 'http://remotehost/api' foreignCom1.createdAt = new Date() await DbCommunity.insert(foreignCom1) @@ -136,7 +137,7 @@ describe('CommunityResolver', () => { foreignCom2.foreign = true foreignCom2.publicKey = Buffer.from('publicKey-ForeignCommunity') foreignCom2.apiVersion = '1_1' - foreignCom2.endPoint = 'http://remotehost' + foreignCom2.endPoint = 'http://remotehost/api' foreignCom2.createdAt = new Date() await DbCommunity.insert(foreignCom2) @@ -144,24 +145,24 @@ describe('CommunityResolver', () => { foreignCom3.foreign = true foreignCom3.publicKey = Buffer.from('publicKey-ForeignCommunity') foreignCom3.apiVersion = '1_2' - foreignCom3.endPoint = 'http://remotehost' + foreignCom3.endPoint = 'http://remotehost/api' foreignCom3.createdAt = new Date() await DbCommunity.insert(foreignCom3) }) - it('returns 3x home and 3x foreign-community entries', async () => { + it('returns 3 home community and 3 foreign community entries', async () => { await expect(query({ query: getCommunities })).resolves.toMatchObject({ data: { getCommunities: [ { - id: 1, - foreign: homeCom1.foreign, + id: 3, + foreign: homeCom3.foreign, publicKey: expect.stringMatching('publicKey-HomeCommunity'), - url: expect.stringMatching('http://localhost/api/1_0'), + url: expect.stringMatching('http://localhost/api/2_0'), lastAnnouncedAt: null, verifiedAt: null, lastErrorAt: null, - createdAt: homeCom1.createdAt.toISOString(), + createdAt: homeCom3.createdAt.toISOString(), updatedAt: null, }, { @@ -176,25 +177,25 @@ describe('CommunityResolver', () => { updatedAt: null, }, { - id: 3, - foreign: homeCom3.foreign, + id: 1, + foreign: homeCom1.foreign, publicKey: expect.stringMatching('publicKey-HomeCommunity'), - url: expect.stringMatching('http://localhost/api/2_0'), + url: expect.stringMatching('http://localhost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, lastErrorAt: null, - createdAt: homeCom3.createdAt.toISOString(), + createdAt: homeCom1.createdAt.toISOString(), updatedAt: null, }, { - id: 4, - foreign: foreignCom1.foreign, + id: 6, + foreign: foreignCom3.foreign, publicKey: expect.stringMatching('publicKey-ForeignCommunity'), - url: expect.stringMatching('http://remotehost/api/1_0'), + url: expect.stringMatching('http://remotehost/api/1_2'), lastAnnouncedAt: null, verifiedAt: null, lastErrorAt: null, - createdAt: foreignCom1.createdAt.toISOString(), + createdAt: foreignCom3.createdAt.toISOString(), updatedAt: null, }, { @@ -209,14 +210,14 @@ describe('CommunityResolver', () => { updatedAt: null, }, { - id: 6, - foreign: foreignCom3.foreign, + id: 4, + foreign: foreignCom1.foreign, publicKey: expect.stringMatching('publicKey-ForeignCommunity'), - url: expect.stringMatching('http://remotehost/api/1_2'), + url: expect.stringMatching('http://remotehost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, lastErrorAt: null, - createdAt: foreignCom3.createdAt.toISOString(), + createdAt: foreignCom1.createdAt.toISOString(), updatedAt: null, }, ], diff --git a/backend/src/graphql/resolver/CommunityResolver.ts b/backend/src/graphql/resolver/CommunityResolver.ts index 86e55ad1f..19a499a9b 100644 --- a/backend/src/graphql/resolver/CommunityResolver.ts +++ b/backend/src/graphql/resolver/CommunityResolver.ts @@ -11,7 +11,11 @@ export class CommunityResolver { @Query(() => [Community]) async getCommunities(): Promise { const dbCommunities: DbCommunity[] = await DbCommunity.find({ - order: { foreign: 'ASC', publicKey: 'ASC', apiVersion: 'ASC' }, + order: { + foreign: 'ASC', + createdAt: 'DESC', + lastAnnouncedAt: 'DESC', + }, }) return dbCommunities.map((dbCom: DbCommunity) => new Community(dbCom)) } diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index da745d705..f20a8c2d1 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -58,7 +58,8 @@ WEBHOOK_ELOPAGE_SECRET=secret # Federation FEDERATION_DHT_CONFIG_VERSION=v2.2023-02-07 -# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen on an hash created from this topic +# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen +# on an hash created from this topic # FEDERATION_DHT_TOPIC=GRADIDO_HUB # FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f FEDERATION_COMMUNITY_URL=http://stage1.gradido.net diff --git a/dht-node/.env.template b/dht-node/.env.template index 243bfc60f..efe6158a6 100644 --- a/dht-node/.env.template +++ b/dht-node/.env.template @@ -9,6 +9,9 @@ DB_DATABASE=gradido_community TYPEORM_LOGGING_RELATIVE_PATH=$TYPEORM_LOGGING_RELATIVE_PATH # Federation +FEDERATION_DHT_CONFIG_VERSION=$FEDERATION_DHT_CONFIG_VERSION +# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen +# on an hash created from this topic FEDERATION_DHT_TOPIC=$FEDERATION_DHT_TOPIC FEDERATION_DHT_SEED=$FEDERATION_DHT_SEED FEDERATION_COMMUNITY_URL=$FEDERATION_COMMUNITY_URL diff --git a/e2e-tests/yarn.lock b/e2e-tests/yarn.lock index c0f623e47..1fffb6870 100644 --- a/e2e-tests/yarn.lock +++ b/e2e-tests/yarn.lock @@ -2193,10 +2193,10 @@ crypto-browserify@^3.0.0: randombytes "^2.0.0" randomfill "^1.0.3" -cypress@^10.4.0: - version "10.8.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.8.0.tgz#12a681f2642b6f13d636bab65d5b71abdb1497a5" - integrity sha512-QVse0dnLm018hgti2enKMVZR9qbIO488YGX06nH5j3Dg1isL38DwrBtyrax02CANU6y8F4EJUuyW6HJKw1jsFA== +cypress@^12.7.0: + version "12.8.1" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-12.8.1.tgz#0c6e67f34554d553138697aaf349b637d80004eb" + integrity sha512-lIFbKdaSYAOarNLHNFa2aPZu6YSF+8UY4VRXMxJrFUnk6RvfG0AWsZ7/qle/aIz30TNUD4aOihz2ZgS4vuQVSA== dependencies: "@cypress/request" "^2.88.10" "@cypress/xvfb" "^1.2.4" @@ -2215,7 +2215,7 @@ cypress@^10.4.0: commander "^5.1.0" common-tags "^1.8.0" dayjs "^1.10.4" - debug "^4.3.2" + debug "^4.3.4" enquirer "^2.3.6" eventemitter2 "6.4.7" execa "4.1.0" diff --git a/federation/.env.template b/federation/.env.template index 5713a7f3f..295c3c480 100644 --- a/federation/.env.template +++ b/federation/.env.template @@ -13,3 +13,6 @@ DB_DATABASE=gradido_community # Federation FEDERATION_COMMUNITY_URL=$FEDERATION_COMMUNITY_URL +FEDERATION_CONFIG_VERSION=$FEDERATION_CONFIG_VERSION +# comma separated list of api-versions, which cause starting several federation modules +FEDERATION_COMMUNITY_APIS=$FEDERATION_COMMUNITY_APIS \ No newline at end of file