diff --git a/admin/src/graphql/updateHomeCommunity.js b/admin/src/graphql/updateHomeCommunity.js index 19bfb7396..036db91e5 100644 --- a/admin/src/graphql/updateHomeCommunity.js +++ b/admin/src/graphql/updateHomeCommunity.js @@ -8,7 +8,7 @@ export const updateHomeCommunity = gql` location: $location hieroTopicId: $hieroTopicId ) { - id + uuid } } ` diff --git a/backend/src/auth/ADMIN_RIGHTS.ts b/backend/src/auth/ADMIN_RIGHTS.ts index 9ba3e7ccd..69100d7d2 100644 --- a/backend/src/auth/ADMIN_RIGHTS.ts +++ b/backend/src/auth/ADMIN_RIGHTS.ts @@ -5,8 +5,6 @@ export const ADMIN_RIGHTS = [ RIGHTS.DELETE_USER, RIGHTS.UNDELETE_USER, RIGHTS.COMMUNITY_UPDATE, - RIGHTS.COMMUNITY_BY_UUID, - RIGHTS.COMMUNITY_BY_IDENTIFIER, - RIGHTS.HOME_COMMUNITY, + RIGHTS.COMMUNITY_WITH_API_KEYS, RIGHTS.PROJECT_BRANDING_MUTATE, ] diff --git a/backend/src/auth/DLT_CONNECTOR_RIGHTS.ts b/backend/src/auth/DLT_CONNECTOR_RIGHTS.ts index 399b7c2d4..9b4c56eaa 100644 --- a/backend/src/auth/DLT_CONNECTOR_RIGHTS.ts +++ b/backend/src/auth/DLT_CONNECTOR_RIGHTS.ts @@ -1,3 +1,3 @@ import { RIGHTS } from './RIGHTS' -export const DLT_CONNECTOR_RIGHTS = [RIGHTS.COMMUNITY_BY_IDENTIFIER, RIGHTS.HOME_COMMUNITY] +export const DLT_CONNECTOR_RIGHTS = [RIGHTS.COMMUNITIES, RIGHTS.COMMUNITY_UPDATE] diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index 012a4e627..d26bdc702 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -69,9 +69,7 @@ export enum RIGHTS { SET_USER_ROLE = 'SET_USER_ROLE', DELETE_USER = 'DELETE_USER', UNDELETE_USER = 'UNDELETE_USER', - COMMUNITY_BY_UUID = 'COMMUNITY_BY_UUID', - COMMUNITY_BY_IDENTIFIER = 'COMMUNITY_BY_IDENTIFIER', - HOME_COMMUNITY = 'HOME_COMMUNITY', COMMUNITY_UPDATE = 'COMMUNITY_UPDATE', + COMMUNITY_WITH_API_KEYS = 'COMMUNITY_WITH_API_KEYS', PROJECT_BRANDING_MUTATE = 'PROJECT_BRANDING_MUTATE', } diff --git a/backend/src/graphql/arg/UserArgs.ts b/backend/src/graphql/arg/UserArgs.ts index 406be14cb..681d3ce51 100644 --- a/backend/src/graphql/arg/UserArgs.ts +++ b/backend/src/graphql/arg/UserArgs.ts @@ -7,7 +7,7 @@ export class UserArgs { @IsString() identifier: string - @Field() + @Field({ nullable: true }) @IsString() - communityIdentifier: string + communityIdentifier?: string } diff --git a/backend/src/graphql/model/AdminCommunityView.ts b/backend/src/graphql/model/AdminCommunityView.ts index 50cee146a..8a685fa86 100644 --- a/backend/src/graphql/model/AdminCommunityView.ts +++ b/backend/src/graphql/model/AdminCommunityView.ts @@ -38,7 +38,6 @@ export class AdminCommunityView { this.updatedAt = dbCom.updatedAt this.uuid = dbCom.communityUuid this.authenticatedAt = dbCom.authenticatedAt - this.gmsApiKey = dbCom.gmsApiKey this.hieroTopicId = dbCom.hieroTopicId if (dbCom.location) { this.location = Point2Location(dbCom.location as Point) diff --git a/backend/src/graphql/model/Community.ts b/backend/src/graphql/model/Community.ts index 62cec9cf7..e5ccad59b 100644 --- a/backend/src/graphql/model/Community.ts +++ b/backend/src/graphql/model/Community.ts @@ -12,7 +12,6 @@ export class Community { this.creationDate = dbCom.creationDate this.uuid = dbCom.communityUuid this.authenticatedAt = dbCom.authenticatedAt - this.gmsApiKey = dbCom.gmsApiKey this.hieroTopicId = dbCom.hieroTopicId } @@ -40,9 +39,6 @@ export class Community { @Field(() => Date, { nullable: true }) authenticatedAt: Date | null - @Field(() => String, { nullable: true }) - gmsApiKey: string | null - @Field(() => String, { nullable: true }) hieroTopicId: string | null } diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index c9c925a2e..5e7d929e2 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -1,5 +1,5 @@ import { ApolloServerTestClient } from 'apollo-server-testing' -import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity } from 'database' +import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity, getHomeCommunity } from 'database' import { GraphQLError } from 'graphql/error/GraphQLError' import { DataSource } from 'typeorm' import { v4 as uuidv4 } from 'uuid' @@ -10,19 +10,20 @@ import { i18n as localization } from '@test/testSetup' import { userFactory } from '@/seeds/factory/user' import { login, updateHomeCommunityQuery } from '@/seeds/graphql/mutations' import { - allCommunities, - communitiesQuery, - getCommunities, + allCommunities, getCommunityByIdentifierQuery, getHomeCommunityQuery, + reachableCommunities, } from '@/seeds/graphql/queries' import { peterLustig } from '@/seeds/users/peter-lustig' +import { createCommunity, createVerifiedFederatedCommunity } from 'database/src/seeds/community' import { getLogger } from 'config-schema/test/testSetup' -import { getCommunityByUuid } from './util/communities' +import { CONFIG } from '@/config' jest.mock('@/password/EncryptorUtils') +CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER = 1000 // to do: We need a setup for the tests that closes the connection let mutate: ApolloServerTestClient['mutate'] @@ -46,11 +47,10 @@ beforeAll(async () => { mutate = testEnv.mutate query = testEnv.query con = testEnv.con - await DbFederatedCommunity.clear() + await cleanDB() }) afterAll(async () => { - await cleanDB() await con.destroy() }) @@ -109,31 +109,38 @@ const ed25519KeyPairStaticHex = [ ] describe('CommunityResolver', () => { - describe('getCommunities', () => { + describe('allCommunities for admin', () => { let homeCom1: DbFederatedCommunity let homeCom2: DbFederatedCommunity let homeCom3: DbFederatedCommunity let foreignCom1: DbFederatedCommunity let foreignCom2: DbFederatedCommunity - let foreignCom3: DbFederatedCommunity + let foreignCom3: DbFederatedCommunity + + beforeAll(async () => { + // create admin and login as admin + await userFactory(testEnv, peterLustig) + await mutate({ mutation: login, variables: peterLoginData }) + }) + + afterAll(async () => { + await cleanDB() + }) describe('with empty list', () => { it('returns no community entry', async () => { // const result: Community[] = await query({ query: getCommunities }) // expect(result.length).toEqual(0) - await expect(query({ query: getCommunities })).resolves.toMatchObject({ + await expect(query({ query: allCommunities })).resolves.toMatchObject({ data: { - getCommunities: [], + allCommunities: [], }, }) }) }) - describe('only home-communities entries', () => { + describe('only home-community entries (different apis)', () => { beforeEach(async () => { - await cleanDB() - jest.clearAllMocks() - homeCom1 = DbFederatedCommunity.create() homeCom1.foreign = false homeCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[0].public, 'hex') @@ -144,7 +151,7 @@ describe('CommunityResolver', () => { homeCom2 = DbFederatedCommunity.create() homeCom2.foreign = false - homeCom2.publicKey = Buffer.from(ed25519KeyPairStaticHex[1].public, 'hex') + homeCom2.publicKey = Buffer.from(ed25519KeyPairStaticHex[0].public, 'hex') homeCom2.apiVersion = '1_1' homeCom2.endPoint = 'http://localhost/api' homeCom2.createdAt = new Date() @@ -152,170 +159,67 @@ describe('CommunityResolver', () => { homeCom3 = DbFederatedCommunity.create() homeCom3.foreign = false - homeCom3.publicKey = Buffer.from(ed25519KeyPairStaticHex[2].public, 'hex') + homeCom3.publicKey = Buffer.from(ed25519KeyPairStaticHex[0].public, 'hex') homeCom3.apiVersion = '2_0' homeCom3.endPoint = 'http://localhost/api' homeCom3.createdAt = new Date() await DbFederatedCommunity.insert(homeCom3) }) - it('returns 3 home-community entries', async () => { - await expect(query({ query: getCommunities })).resolves.toMatchObject({ + it('returns only home-community entries', async () => { + await expect(query({ query: allCommunities })).resolves.toMatchObject({ data: { - getCommunities: [ + allCommunities: [ { - id: 3, - foreign: homeCom3.foreign, - publicKey: expect.stringMatching(ed25519KeyPairStaticHex[2].public), - endPoint: expect.stringMatching('http://localhost/api/'), - apiVersion: '2_0', - lastAnnouncedAt: null, - verifiedAt: null, - lastErrorAt: null, - createdAt: homeCom3.createdAt.toISOString(), - updatedAt: null, - }, - { - id: 2, - foreign: homeCom2.foreign, - publicKey: expect.stringMatching(ed25519KeyPairStaticHex[1].public), - endPoint: expect.stringMatching('http://localhost/api/'), - apiVersion: '1_1', - lastAnnouncedAt: null, - verifiedAt: null, - lastErrorAt: null, - createdAt: homeCom2.createdAt.toISOString(), - updatedAt: null, - }, - { - id: 1, - foreign: homeCom1.foreign, + foreign: false, + url: 'http://localhost', publicKey: expect.stringMatching(ed25519KeyPairStaticHex[0].public), - endPoint: expect.stringMatching('http://localhost/api/'), - apiVersion: '1_0', - lastAnnouncedAt: null, - verifiedAt: null, - lastErrorAt: null, - createdAt: homeCom1.createdAt.toISOString(), + authenticatedAt: null, + createdAt: null, + creationDate: null, + description: null, + gmsApiKey: null, + name: null, updatedAt: null, + uuid: null, + federatedCommunities: [ + { + id: 3, + apiVersion: '2_0', + endPoint: 'http://localhost/api/', + createdAt: homeCom3.createdAt.toISOString(), + lastAnnouncedAt: null, + lastErrorAt: null, + updatedAt: null, + verifiedAt: null, + }, + { + id: 2, + apiVersion: '1_1', + endPoint: 'http://localhost/api/', + createdAt: homeCom2.createdAt.toISOString(), + lastAnnouncedAt: null, + lastErrorAt: null, + updatedAt: null, + verifiedAt: null, + }, + { + id: 1, + apiVersion: '1_0', + endPoint: 'http://localhost/api/', + createdAt: homeCom1.createdAt.toISOString(), + lastAnnouncedAt: null, + lastErrorAt: null, + updatedAt: null, + verifiedAt: null, + }, + ], }, ], }, }) }) }) - - describe('plus foreign-communities entries', () => { - beforeEach(async () => { - jest.clearAllMocks() - - foreignCom1 = DbFederatedCommunity.create() - foreignCom1.foreign = true - foreignCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[3].public, 'hex') - foreignCom1.apiVersion = '1_0' - foreignCom1.endPoint = 'http://remotehost/api' - foreignCom1.createdAt = new Date() - await DbFederatedCommunity.insert(foreignCom1) - - foreignCom2 = DbFederatedCommunity.create() - foreignCom2.foreign = true - foreignCom2.publicKey = Buffer.from(ed25519KeyPairStaticHex[4].public, 'hex') - foreignCom2.apiVersion = '1_1' - foreignCom2.endPoint = 'http://remotehost/api' - foreignCom2.createdAt = new Date() - await DbFederatedCommunity.insert(foreignCom2) - - foreignCom3 = DbFederatedCommunity.create() - foreignCom3.foreign = true - foreignCom3.publicKey = Buffer.from(ed25519KeyPairStaticHex[5].public, 'hex') - foreignCom3.apiVersion = '2_0' - foreignCom3.endPoint = 'http://remotehost/api' - foreignCom3.createdAt = new Date() - await DbFederatedCommunity.insert(foreignCom3) - }) - - it('returns 3 home community and 3 foreign community entries', async () => { - await expect(query({ query: getCommunities })).resolves.toMatchObject({ - data: { - getCommunities: [ - { - id: 3, - foreign: homeCom3.foreign, - publicKey: expect.stringMatching(ed25519KeyPairStaticHex[2].public), - endPoint: expect.stringMatching('http://localhost/api/'), - apiVersion: '2_0', - lastAnnouncedAt: null, - verifiedAt: null, - lastErrorAt: null, - createdAt: homeCom3.createdAt.toISOString(), - updatedAt: null, - }, - { - id: 2, - foreign: homeCom2.foreign, - publicKey: expect.stringMatching(ed25519KeyPairStaticHex[1].public), - endPoint: expect.stringMatching('http://localhost/api/'), - apiVersion: '1_1', - lastAnnouncedAt: null, - verifiedAt: null, - lastErrorAt: null, - createdAt: homeCom2.createdAt.toISOString(), - updatedAt: null, - }, - { - id: 1, - foreign: homeCom1.foreign, - publicKey: expect.stringMatching(ed25519KeyPairStaticHex[0].public), - endPoint: expect.stringMatching('http://localhost/api/'), - apiVersion: '1_0', - lastAnnouncedAt: null, - verifiedAt: null, - lastErrorAt: null, - createdAt: homeCom1.createdAt.toISOString(), - updatedAt: null, - }, - { - id: 6, - foreign: foreignCom3.foreign, - publicKey: expect.stringMatching(ed25519KeyPairStaticHex[5].public), - endPoint: expect.stringMatching('http://remotehost/api/'), - apiVersion: '2_0', - lastAnnouncedAt: null, - verifiedAt: null, - lastErrorAt: null, - createdAt: foreignCom3.createdAt.toISOString(), - updatedAt: null, - }, - { - id: 5, - foreign: foreignCom2.foreign, - publicKey: expect.stringMatching(ed25519KeyPairStaticHex[4].public), - endPoint: expect.stringMatching('http://remotehost/api/'), - apiVersion: '1_1', - lastAnnouncedAt: null, - verifiedAt: null, - lastErrorAt: null, - createdAt: foreignCom2.createdAt.toISOString(), - updatedAt: null, - }, - { - id: 4, - foreign: foreignCom1.foreign, - publicKey: expect.stringMatching(ed25519KeyPairStaticHex[3].public), - endPoint: expect.stringMatching('http://remotehost/api/'), - apiVersion: '1_0', - lastAnnouncedAt: null, - verifiedAt: null, - lastErrorAt: null, - createdAt: foreignCom1.createdAt.toISOString(), - updatedAt: null, - }, - ], - }, - }) - }) - }) - describe('with 6 federated community entries', () => { let comHomeCom1: DbCommunity let comForeignCom1: DbCommunity @@ -323,7 +227,6 @@ describe('CommunityResolver', () => { let foreignCom4: DbFederatedCommunity beforeEach(async () => { - jest.clearAllMocks() comHomeCom1 = DbCommunity.create() comHomeCom1.foreign = false comHomeCom1.url = 'http://localhost' @@ -360,6 +263,30 @@ describe('CommunityResolver', () => { comForeignCom2.creationDate = new Date() await DbCommunity.insert(comForeignCom2) + foreignCom1 = DbFederatedCommunity.create() + foreignCom1.foreign = true + foreignCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[3].public, 'hex') + foreignCom1.apiVersion = '1_0' + foreignCom1.endPoint = 'http://remotehost/api' + foreignCom1.createdAt = new Date() + await DbFederatedCommunity.insert(foreignCom1) + + foreignCom2 = DbFederatedCommunity.create() + foreignCom2.foreign = true + foreignCom2.publicKey = Buffer.from(ed25519KeyPairStaticHex[4].public, 'hex') + foreignCom2.apiVersion = '1_1' + foreignCom2.endPoint = 'http://remotehost/api' + foreignCom2.createdAt = new Date() + await DbFederatedCommunity.insert(foreignCom2) + + foreignCom3 = DbFederatedCommunity.create() + foreignCom3.foreign = true + foreignCom3.publicKey = Buffer.from(ed25519KeyPairStaticHex[5].public, 'hex') + foreignCom3.apiVersion = '2_0' + foreignCom3.endPoint = 'http://remotehost/api' + foreignCom3.createdAt = new Date() + await DbFederatedCommunity.insert(foreignCom3) + foreignCom4 = DbFederatedCommunity.create() foreignCom4.foreign = true foreignCom4.publicKey = Buffer.from(ed25519KeyPairStaticHex[5].public, 'hex') @@ -376,15 +303,15 @@ describe('CommunityResolver', () => { { foreign: false, url: 'http://localhost', - publicKey: expect.stringMatching(ed25519KeyPairStaticHex[2].public), - authenticatedAt: null, - createdAt: null, - creationDate: null, - description: null, + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[0].public), + authenticatedAt: comHomeCom1.authenticatedAt?.toISOString(), + createdAt: comHomeCom1.createdAt.toISOString(), + creationDate: comHomeCom1.creationDate?.toISOString(), + description: comHomeCom1.description, gmsApiKey: null, - name: null, + name: comHomeCom1.name, updatedAt: null, - uuid: null, + uuid: comHomeCom1.communityUuid, federatedCommunities: [ { id: 3, @@ -396,21 +323,6 @@ describe('CommunityResolver', () => { updatedAt: null, verifiedAt: null, }, - ], - }, - { - foreign: false, - url: 'http://localhost', - publicKey: expect.stringMatching(ed25519KeyPairStaticHex[1].public), - authenticatedAt: null, - createdAt: null, - creationDate: null, - description: null, - gmsApiKey: null, - name: null, - updatedAt: null, - uuid: null, - federatedCommunities: [ { id: 2, apiVersion: '1_1', @@ -421,21 +333,6 @@ describe('CommunityResolver', () => { updatedAt: null, verifiedAt: null, }, - ], - }, - { - foreign: false, - url: 'http://localhost', - publicKey: expect.stringMatching(ed25519KeyPairStaticHex[0].public), - authenticatedAt: comHomeCom1.authenticatedAt?.toISOString(), - createdAt: comHomeCom1.createdAt.toISOString(), - creationDate: comHomeCom1.creationDate?.toISOString(), - description: comHomeCom1.description, - gmsApiKey: null, - name: comHomeCom1.name, - updatedAt: null, - uuid: comHomeCom1.communityUuid, - federatedCommunities: [ { id: 1, apiVersion: '1_0', @@ -540,23 +437,21 @@ describe('CommunityResolver', () => { }) }) - describe('communities', () => { + describe('reachableCommunities', () => { let homeCom1: DbCommunity let foreignCom1: DbCommunity let foreignCom2: DbCommunity - describe('with empty list', () => { - beforeEach(async () => { - await cleanDB() - jest.clearAllMocks() - }) + afterAll(async () => { + await DbCommunity.clear() + await DbFederatedCommunity.clear() + }) + describe('with empty list', () => { it('returns no community entry', async () => { - // const result: Community[] = await query({ query: getCommunities }) - // expect(result.length).toEqual(0) - await expect(query({ query: communitiesQuery })).resolves.toMatchObject({ + await expect(query({ query: reachableCommunities })).resolves.toMatchObject({ data: { - communities: [], + reachableCommunities: [], }, }) }) @@ -564,35 +459,20 @@ describe('CommunityResolver', () => { describe('with one home-community entry', () => { beforeEach(async () => { - await cleanDB() - jest.clearAllMocks() - - homeCom1 = DbCommunity.create() - homeCom1.foreign = false - homeCom1.url = 'http://localhost/api' - homeCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[0].public, 'hex') - homeCom1.privateKey = Buffer.from(ed25519KeyPairStaticHex[0].private, 'hex') - homeCom1.communityUuid = 'HomeCom-UUID' - homeCom1.authenticatedAt = new Date() - homeCom1.name = 'HomeCommunity-name' - homeCom1.description = 'HomeCommunity-description' - homeCom1.creationDate = new Date() + homeCom1 = await createCommunity(false, false) await DbCommunity.insert(homeCom1) }) it('returns 1 home-community entry', async () => { - await expect(query({ query: communitiesQuery })).resolves.toMatchObject({ + await expect(query({ query: reachableCommunities })).resolves.toMatchObject({ data: { - communities: [ + reachableCommunities: [ { - id: expect.any(Number), foreign: homeCom1.foreign, name: homeCom1.name, description: homeCom1.description, url: homeCom1.url, - creationDate: homeCom1.creationDate?.toISOString(), uuid: homeCom1.communityUuid, - authenticatedAt: homeCom1.authenticatedAt?.toISOString(), }, ], }, @@ -602,135 +482,55 @@ describe('CommunityResolver', () => { describe('returns 2 filtered communities even with 3 existing entries', () => { beforeEach(async () => { - await cleanDB() - jest.clearAllMocks() - - homeCom1 = DbCommunity.create() - homeCom1.foreign = false - homeCom1.url = 'http://localhost/api' - homeCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[0].public, 'hex') - homeCom1.privateKey = Buffer.from(ed25519KeyPairStaticHex[0].private, 'hex') - homeCom1.communityUuid = 'HomeCom-UUID' - homeCom1.authenticatedAt = new Date() - homeCom1.name = 'HomeCommunity-name' - homeCom1.description = 'HomeCommunity-description' - homeCom1.creationDate = new Date() - await DbCommunity.insert(homeCom1) - - foreignCom1 = DbCommunity.create() - foreignCom1.foreign = true - foreignCom1.url = 'http://stage-2.gradido.net/api' - foreignCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[3].public, 'hex') - foreignCom1.privateKey = Buffer.from(ed25519KeyPairStaticHex[3].private, 'hex') - // foreignCom1.communityUuid = 'Stage2-Com-UUID' - // foreignCom1.authenticatedAt = new Date() - foreignCom1.name = 'Stage-2_Community-name' - foreignCom1.description = 'Stage-2_Community-description' - foreignCom1.creationDate = new Date() - await DbCommunity.insert(foreignCom1) - - foreignCom2 = DbCommunity.create() - foreignCom2.foreign = true - foreignCom2.url = 'http://stage-3.gradido.net/api' - foreignCom2.publicKey = Buffer.from(ed25519KeyPairStaticHex[4].public, 'hex') - foreignCom2.privateKey = Buffer.from(ed25519KeyPairStaticHex[4].private, 'hex') - foreignCom2.communityUuid = 'Stage3-Com-UUID' - foreignCom2.authenticatedAt = new Date() - foreignCom2.name = 'Stage-3_Community-name' - foreignCom2.description = 'Stage-3_Community-description' - foreignCom2.creationDate = new Date() - await DbCommunity.insert(foreignCom2) + foreignCom1 = await createCommunity(true, false) + foreignCom2 = await createCommunity(true, false) + const com1FedCom = await createVerifiedFederatedCommunity('1_0', 100, foreignCom1, false) + const com1FedCom2 = await createVerifiedFederatedCommunity('1_1', 100, foreignCom1, false) + const com2FedCom = await createVerifiedFederatedCommunity('1_0', 10000, foreignCom2, false) + await Promise.all([ + DbCommunity.insert(foreignCom1), + DbCommunity.insert(foreignCom2), + DbFederatedCommunity.insert(com1FedCom), + DbFederatedCommunity.insert(com1FedCom2), + DbFederatedCommunity.insert(com2FedCom) + ]) }) it('returns 2 community entries', async () => { - await expect(query({ query: communitiesQuery })).resolves.toMatchObject({ - data: { - communities: [ - { - id: expect.any(Number), - foreign: homeCom1.foreign, - name: homeCom1.name, - description: homeCom1.description, - url: homeCom1.url, - creationDate: homeCom1.creationDate?.toISOString(), - uuid: homeCom1.communityUuid, - authenticatedAt: homeCom1.authenticatedAt?.toISOString(), - }, - /* - { - id: expect.any(Number), - foreign: foreignCom1.foreign, - name: foreignCom1.name, - description: foreignCom1.description, - url: foreignCom1.url, - creationDate: foreignCom1.creationDate?.toISOString(), - uuid: foreignCom1.communityUuid, - authenticatedAt: foreignCom1.authenticatedAt?.toISOString(), - }, - */ - { - id: expect.any(Number), - foreign: foreignCom2.foreign, - name: foreignCom2.name, - description: foreignCom2.description, - url: foreignCom2.url, - creationDate: foreignCom2.creationDate?.toISOString(), - uuid: foreignCom2.communityUuid, - authenticatedAt: foreignCom2.authenticatedAt?.toISOString(), - }, - ], - }, - }) + const result = await query({ query: reachableCommunities }) + expect(result.data.reachableCommunities.length).toBe(2) + expect(result.data.reachableCommunities).toMatchObject([ + { + foreign: homeCom1.foreign, + name: homeCom1.name, + description: homeCom1.description, + url: homeCom1.url, + uuid: homeCom1.communityUuid, + }, { + foreign: foreignCom1.foreign, + name: foreignCom1.name, + description: foreignCom1.description, + url: foreignCom1.url, + uuid: foreignCom1.communityUuid, + } + ]) }) }) describe('search community by uuid', () => { let homeCom: DbCommunity | null - beforeEach(async () => { - await cleanDB() - jest.clearAllMocks() - const admin = await userFactory(testEnv, peterLustig) - // login as admin - await mutate({ mutation: login, variables: peterLoginData }) + beforeAll(async () => { + await DbCommunity.clear() - // HomeCommunity is still created in userFactory - homeCom = await getCommunityByUuid(admin.communityUuid) + homeCom = await createCommunity(false, false) + foreignCom1 = await createCommunity(true, false) + foreignCom2 = await createCommunity(true, false) - foreignCom1 = DbCommunity.create() - foreignCom1.foreign = true - foreignCom1.url = 'http://stage-2.gradido.net/api' - foreignCom1.publicKey = Buffer.from( - '8a1f9374b99c30d827b85dcd23f7e50328430d64ef65ef35bf375ea8eb9a2e1d', - 'hex', - ) - foreignCom1.privateKey = Buffer.from( - 'f6c2a9d78e20a3c910f35b8ffcf824aa7b37f0d3d81bfc4c0e65e17a194b3a4a', - 'hex', - ) - // foreignCom1.communityUuid = 'Stage2-Com-UUID' - // foreignCom1.authenticatedAt = new Date() - foreignCom1.name = 'Stage-2_Community-name' - foreignCom1.description = 'Stage-2_Community-description' - foreignCom1.creationDate = new Date() - await DbCommunity.insert(foreignCom1) - - foreignCom2 = DbCommunity.create() - foreignCom2.foreign = true - foreignCom2.url = 'http://stage-3.gradido.net/api' - foreignCom2.publicKey = Buffer.from( - 'e047365a54082e8a7e9273da61b55c8134a2a0c836799ba12b78b9b0c52bc85f', - 'hex', - ) - foreignCom2.privateKey = Buffer.from( - 'e047365a54082e8a7e9273da61b55c8134a2a0c836799ba12b78b9b0c52bc85f', - 'hex', - ) - foreignCom2.communityUuid = uuidv4() - foreignCom2.authenticatedAt = new Date() - foreignCom2.name = 'Stage-3_Community-name' - foreignCom2.description = 'Stage-3_Community-description' - foreignCom2.creationDate = new Date() - await DbCommunity.insert(foreignCom2) + await Promise.all([ + DbCommunity.insert(homeCom), + DbCommunity.insert(foreignCom1), + DbCommunity.insert(foreignCom2), + ]) }) it('finds the home-community by uuid', async () => { @@ -749,7 +549,6 @@ describe('CommunityResolver', () => { url: homeCom?.url, creationDate: homeCom?.creationDate?.toISOString(), uuid: homeCom?.communityUuid, - authenticatedAt: homeCom?.authenticatedAt, }, }, }) @@ -769,76 +568,100 @@ describe('CommunityResolver', () => { description: homeCom?.description, url: homeCom?.url, creationDate: homeCom?.creationDate?.toISOString(), - uuid: homeCom?.communityUuid, - authenticatedAt: homeCom?.authenticatedAt, + uuid: homeCom?.communityUuid }, }, }) }) - - it('updates the home-community gmsApiKey', async () => { - await expect( - mutate({ - mutation: updateHomeCommunityQuery, - variables: { uuid: homeCom?.communityUuid, gmsApiKey: 'gmsApiKey' }, - }), - ).resolves.toMatchObject({ - data: { - updateHomeCommunity: { - id: expect.any(Number), - foreign: homeCom?.foreign, - name: homeCom?.name, - description: homeCom?.description, - url: homeCom?.url, - creationDate: homeCom?.creationDate?.toISOString(), - uuid: homeCom?.communityUuid, - authenticatedAt: homeCom?.authenticatedAt, - gmsApiKey: 'gmsApiKey', - }, - }, - }) - }) - - it('throws error on updating a foreign-community', async () => { - expect( - await mutate({ - mutation: updateHomeCommunityQuery, - variables: { uuid: foreignCom2.communityUuid, gmsApiKey: 'gmsApiKey' }, - }), - ).toEqual( - expect.objectContaining({ - errors: [new GraphQLError('Error: Only the HomeCommunity could be modified!')], - }), - ) - }) - - it('throws error on updating a community without uuid', async () => { - expect( - await mutate({ - mutation: updateHomeCommunityQuery, - variables: { uuid: null, gmsApiKey: 'gmsApiKey' }, - }), - ).toEqual( - expect.objectContaining({ - errors: [ - new GraphQLError(`Variable "$uuid" of non-null type "String!" must not be null.`), - ], - }), - ) - }) - - it('throws error on updating a community with not existing uuid', async () => { - expect( - await mutate({ - mutation: updateHomeCommunityQuery, - variables: { uuid: uuidv4(), gmsApiKey: 'gmsApiKey' }, - }), - ).toEqual( - expect.objectContaining({ - errors: [new GraphQLError('HomeCommunity with uuid not found: ')], - }), - ) - }) + }) + }) + + describe('update community', () => { + let homeCom: DbCommunity + let foreignCom1: DbCommunity + let foreignCom2: DbCommunity + + beforeAll(async () => { + await DbCommunity.clear() + + // create admin and login as admin + await userFactory(testEnv, peterLustig) + homeCom = (await getHomeCommunity())! + foreignCom1 = await createCommunity(true, false) + foreignCom2 = await createCommunity(true, false) + + await Promise.all([ + DbCommunity.insert(foreignCom1), + DbCommunity.insert(foreignCom2), + mutate({ mutation: login, variables: peterLoginData }) + ]) + }) + + afterAll(async () => { + await cleanDB() + }) + + it('updates the home-community gmsApiKey', async () => { + await expect( + mutate({ + mutation: updateHomeCommunityQuery, + variables: { uuid: homeCom?.communityUuid, gmsApiKey: 'gmsApiKey' }, + }), + ).resolves.toMatchObject({ + data: { + updateHomeCommunity: { + foreign: homeCom?.foreign, + name: homeCom?.name, + description: homeCom?.description, + url: homeCom?.url, + creationDate: homeCom?.creationDate?.toISOString(), + uuid: homeCom?.communityUuid, + authenticatedAt: homeCom?.authenticatedAt, + gmsApiKey: 'gmsApiKey', + }, + }, + }) + }) + + it('throws error on updating a foreign-community', async () => { + expect( + await mutate({ + mutation: updateHomeCommunityQuery, + variables: { uuid: foreignCom2.communityUuid, gmsApiKey: 'gmsApiKey' }, + }), + ).toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Error: Only the HomeCommunity could be modified!')], + }), + ) + }) + + it('throws error on updating a community without uuid', async () => { + expect( + await mutate({ + mutation: updateHomeCommunityQuery, + variables: { uuid: null, gmsApiKey: 'gmsApiKey' }, + }), + ).toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError(`Variable "$uuid" of non-null type "String!" must not be null.`), + ], + }), + ) + }) + + it('throws error on updating a community with not existing uuid', async () => { + expect( + await mutate({ + mutation: updateHomeCommunityQuery, + variables: { uuid: uuidv4(), gmsApiKey: 'gmsApiKey' }, + }), + ).toEqual( + expect.objectContaining({ + errors: [new GraphQLError('HomeCommunity with uuid not found: ')], + }), + ) }) }) }) diff --git a/backend/src/graphql/resolver/CommunityResolver.ts b/backend/src/graphql/resolver/CommunityResolver.ts index a46e30144..675ec858f 100644 --- a/backend/src/graphql/resolver/CommunityResolver.ts +++ b/backend/src/graphql/resolver/CommunityResolver.ts @@ -1,12 +1,14 @@ -import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity, getHomeCommunity } from 'database' +import { + Community as DbCommunity, + getReachableCommunities, + getHomeCommunity +} from 'database' import { Arg, Args, Authorized, Mutation, Query, Resolver } from 'type-graphql' -import { IsNull, Not } from 'typeorm' import { Paginated } from '@arg/Paginated' import { EditCommunityInput } from '@input/EditCommunityInput' import { AdminCommunityView } from '@model/AdminCommunityView' import { Community } from '@model/Community' -import { FederatedCommunity } from '@model/FederatedCommunity' import { RIGHTS } from '@/auth/RIGHTS' import { LogError } from '@/server/LogError' @@ -18,24 +20,11 @@ import { getCommunityByUuid, } from './util/communities' +import { CONFIG } from '@/config' + @Resolver() export class CommunityResolver { - @Authorized([RIGHTS.COMMUNITIES]) - @Query(() => [FederatedCommunity]) - async getCommunities(): Promise { - const dbFederatedCommunities: DbFederatedCommunity[] = await DbFederatedCommunity.find({ - order: { - foreign: 'ASC', - createdAt: 'DESC', - lastAnnouncedAt: 'DESC', - }, - }) - return dbFederatedCommunities.map( - (dbCom: DbFederatedCommunity) => new FederatedCommunity(dbCom), - ) - } - - @Authorized([RIGHTS.COMMUNITIES]) + @Authorized([RIGHTS.COMMUNITY_WITH_API_KEYS]) @Query(() => [AdminCommunityView]) async allCommunities(@Args() paginated: Paginated): Promise { // communityUUID could be oneTimePassCode (uint32 number) @@ -44,17 +33,17 @@ export class CommunityResolver { @Authorized([RIGHTS.COMMUNITIES]) @Query(() => [Community]) - async communities(): Promise { - const dbCommunities: DbCommunity[] = await DbCommunity.find({ - where: { communityUuid: Not(IsNull()) }, //, authenticatedAt: Not(IsNull()) }, - order: { - name: 'ASC', - }, + async reachableCommunities(): Promise { + const dbCommunities: DbCommunity[] = await getReachableCommunities( + CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER * 2, { + // order by + foreign: 'ASC', // home community first + name: 'ASC', // sort foreign communities by name }) return dbCommunities.map((dbCom: DbCommunity) => new Community(dbCom)) } - @Authorized([RIGHTS.COMMUNITY_BY_IDENTIFIER]) + @Authorized([RIGHTS.COMMUNITIES]) @Query(() => Community) async communityByIdentifier( @Arg('communityIdentifier') communityIdentifier: string, @@ -67,7 +56,7 @@ export class CommunityResolver { return new Community(community) } - @Authorized([RIGHTS.HOME_COMMUNITY]) + @Authorized([RIGHTS.COMMUNITIES]) @Query(() => Community) async homeCommunity(): Promise { const community = await getHomeCommunity() @@ -78,10 +67,10 @@ export class CommunityResolver { } @Authorized([RIGHTS.COMMUNITY_UPDATE]) - @Mutation(() => Community) + @Mutation(() => AdminCommunityView) async updateHomeCommunity( @Args() { uuid, gmsApiKey, location, hieroTopicId }: EditCommunityInput, - ): Promise { + ): Promise { const homeCom = await getCommunityByUuid(uuid) if (!homeCom) { throw new LogError('HomeCommunity with uuid not found: ', uuid) @@ -101,6 +90,6 @@ export class CommunityResolver { homeCom.hieroTopicId = hieroTopicId ?? null await DbCommunity.save(homeCom) } - return new Community(homeCom) + return new AdminCommunityView(homeCom) } } diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 8acbd7b53..faae12e56 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -14,7 +14,7 @@ import { User } from '@model/User' import { QueryLinkResult } from '@union/QueryLinkResult' import { Decay, interpretEncryptedTransferArgs, TransactionTypeId } from 'core' import { - AppDatabase, Community as DbCommunity, Contribution as DbContribution, + AppDatabase, Contribution as DbContribution, ContributionLink as DbContributionLink, FederatedCommunity as DbFederatedCommunity, Transaction as DbTransaction, TransactionLink as DbTransactionLink, User as DbUser, @@ -36,7 +36,7 @@ import { Context, getClientTimezoneOffset, getUser } from '@/server/context' import { calculateBalance } from '@/util/validate' import { fullName } from 'core' import { TRANSACTION_LINK_LOCK, TRANSACTIONS_LOCK } from 'database' -import { calculateDecay, decode, DisburseJwtPayloadType, encode, encryptAndSign, EncryptedJWEJwtPayloadType, RedeemJwtPayloadType, verify } from 'shared' +import { calculateDecay, compoundInterest, decayFormula, decode, DisburseJwtPayloadType, encode, encryptAndSign, EncryptedJWEJwtPayloadType, RedeemJwtPayloadType, verify } from 'shared' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { DisbursementClient as V1_0_DisbursementClient } from '@/federation/client/1_0/DisbursementClient' @@ -48,7 +48,6 @@ import { randombytes_random } from 'sodium-native' import { executeTransaction } from './TransactionResolver' import { getAuthenticatedCommunities, - getCommunityByIdentifier, getCommunityByPublicKey, getCommunityByUuid, } from './util/communities' @@ -90,7 +89,7 @@ export class TransactionLinkResolver { const createdDate = new Date() const validUntil = transactionLinkExpireDate(createdDate) - const holdAvailableAmount = amount.minus(calculateDecay(amount, createdDate, validUntil).decay) + const holdAvailableAmount = compoundInterest(amount, CODE_VALID_DAYS_DURATION * 24 * 60 * 60) // validate amount const sendBalance = await calculateBalance(user.id, holdAvailableAmount.mul(-1), createdDate) diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index c9d68de35..a61356e29 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -439,9 +439,7 @@ export class TransactionResolver { logger.debug( `sendCoins(recipientCommunityIdentifier=${recipientCommunityIdentifier}, recipientIdentifier=${recipientIdentifier}, amount=${amount}, memo=${memo})`, ) - const homeCom = await DbCommunity.findOneOrFail({ where: { foreign: false } }) const senderUser = getUser(context) - if (!recipientCommunityIdentifier || (await isHomeCommunity(recipientCommunityIdentifier))) { // processing sendCoins within sender and recipient are both in home community const recipientUser = await findUserByIdentifier( diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 045ca7756..e13391a55 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -1151,6 +1151,12 @@ export class UserResolver { @Args() { identifier, communityIdentifier }: UserArgs, ): Promise { + // check if identifier contain community and user identifier + if (identifier.includes('/')) { + const parts = identifier.split('/') + communityIdentifier = parts[0] + identifier = parts[1] + } const foundDbUser = await findUserByIdentifier(identifier, communityIdentifier) if (!foundDbUser) { createLogger().debug('User not found', identifier, communityIdentifier) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index ec0a966a8..e42e738f2 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -375,7 +375,6 @@ export const logout = gql` export const updateHomeCommunityQuery = gql` mutation ($uuid: String!, $gmsApiKey: String!) { updateHomeCommunity(uuid: $uuid, gmsApiKey: $gmsApiKey) { - id foreign name description diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index 5a8e06cc0..2eb56e6f6 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -135,18 +135,14 @@ export const listGDTEntriesQuery = gql` } ` -export const communitiesQuery = gql` - query { - communities { - id +export const reachableCommunities = gql` + query { + reachableCommunities { foreign + uuid name description url - creationDate - uuid - authenticatedAt - gmsApiKey } } ` @@ -162,7 +158,6 @@ export const getCommunityByIdentifierQuery = gql` creationDate uuid authenticatedAt - gmsApiKey } } ` @@ -178,24 +173,6 @@ export const getHomeCommunityQuery = gql` creationDate uuid authenticatedAt - gmsApiKey - } - } -` - -export const getCommunities = gql` - query { - getCommunities { - id - foreign - publicKey - endPoint - apiVersion - lastAnnouncedAt - verifiedAt - lastErrorAt - createdAt - updatedAt } } ` @@ -268,7 +245,7 @@ export const listContributions = gql` } ` -export const listAllContributions = ` +export const listAllContributions = gql` query ($pagination: Paginated!) { listAllContributions(pagination: $pagination) { contributionCount diff --git a/database/src/queries/communities.test.ts b/database/src/queries/communities.test.ts index 9cfb210db..18975256c 100644 --- a/database/src/queries/communities.test.ts +++ b/database/src/queries/communities.test.ts @@ -1,8 +1,8 @@ -import { Community as DbCommunity } from '..' +import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity } from '..' import { AppDatabase } from '../AppDatabase' -import { getHomeCommunity } from './communities' -import { describe, expect, it, beforeAll, afterAll } from 'vitest' -import { createCommunity } from '../seeds/homeCommunity' +import { getHomeCommunity, getReachableCommunities } from './communities' +import { describe, expect, it, beforeEach, beforeAll, afterAll } from 'vitest' +import { createCommunity, createVerifiedFederatedCommunity } from '../seeds/community' const db = AppDatabase.getInstance() @@ -14,8 +14,10 @@ afterAll(async () => { }) describe('community.queries', () => { - beforeAll(async () => { + // clean db for every test case + beforeEach(async () => { await DbCommunity.clear() + await DbFederatedCommunity.clear() }) describe('getHomeCommunity', () => { it('should return null if no home community exists', async () => { @@ -37,4 +39,51 @@ describe('community.queries', () => { expect(community?.privateKey).toStrictEqual(homeCom.privateKey) }) }) + describe('getReachableCommunities', () => { + it('home community counts also to reachable communities', async () => { + await createCommunity(false) + expect(await getReachableCommunities(1000)).toHaveLength(1) + }) + it('foreign communities authenticated within chosen range', async () => { + const com1 = await createCommunity(true) + const com2 = await createCommunity(true) + const com3 = await createCommunity(true) + await createVerifiedFederatedCommunity('1_0', 100, com1) + await createVerifiedFederatedCommunity('1_0', 500, com2) + // outside of range + await createVerifiedFederatedCommunity('1_0', 1200, com3) + + const communities = await getReachableCommunities(1000) + expect(communities).toHaveLength(2) + expect(communities[0].communityUuid).toBe(com1.communityUuid) + expect(communities[1].communityUuid).toBe(com2.communityUuid) + }) + it('multiple federated community api version, result in one community', async () => { + const com1 = await createCommunity(true) + await createVerifiedFederatedCommunity('1_0', 100, com1) + await createVerifiedFederatedCommunity('1_1', 100, com1) + expect(await getReachableCommunities(1000)).toHaveLength(1) + }) + it('multiple federated community api version one outside of range, result in one community', async () => { + const com1 = await createCommunity(true) + await createVerifiedFederatedCommunity('1_0', 100, com1) + // outside of range + await createVerifiedFederatedCommunity('1_1', 1200, com1) + expect(await getReachableCommunities(1000)).toHaveLength(1) + }) + it('foreign and home community', async () => { + // home community + await createCommunity(false) + const com1 = await createCommunity(true) + const com2 = await createCommunity(true) + await createVerifiedFederatedCommunity('1_0', 400, com1) + await createVerifiedFederatedCommunity('1_0', 1200, com2) + expect(await getReachableCommunities(1000)).toHaveLength(2) + }) + it('not verified inside time frame federated community', async () => { + const com1 = await createCommunity(true) + await createVerifiedFederatedCommunity('1_0', 1200, com1) + expect(await getReachableCommunities(1000)).toHaveLength(0) + }) + }) }) \ No newline at end of file diff --git a/database/src/queries/communities.ts b/database/src/queries/communities.ts index edc3bd7ed..e216f8af6 100644 --- a/database/src/queries/communities.ts +++ b/database/src/queries/communities.ts @@ -1,10 +1,14 @@ +import { FindOptionsOrder, FindOptionsWhere, IsNull, MoreThanOrEqual, Not } from 'typeorm' import { Community as DbCommunity } from '../entity' +import { urlSchema, uuidv4Schema } from 'shared' /** * Retrieves the home community, i.e., a community that is not foreign. * @returns A promise that resolves to the home community, or null if no home community was found */ export async function getHomeCommunity(): Promise { + // TODO: Put in Cache, it is needed nearly always + // TODO: return only DbCommunity or throw to reduce unnecessary checks, because there should be always a home community return await DbCommunity.findOne({ where: { foreign: false }, }) @@ -15,3 +19,45 @@ export async function getCommunityByUuid(communityUuid: string): Promise { + const where: FindOptionsWhere = {} + // pre filter identifier type to reduce db query complexity + if (urlSchema.safeParse(communityIdentifier).success) { + where.url = communityIdentifier + } else if (uuidv4Schema.safeParse(communityIdentifier).success) { + where.communityUuid = communityIdentifier + } else { + where.name = communityIdentifier + } + return where +} + +export async function getCommunityWithFederatedCommunityByIdentifier( + communityIdentifier: string, +): Promise { + return await DbCommunity.findOne({ + where: { ...findWithCommunityIdentifier(communityIdentifier) }, + relations: ['federatedCommunities'], + }) +} + +// returns all reachable communities +// home community and all federated communities which have been verified within the last authenticationTimeoutMs +export async function getReachableCommunities( + authenticationTimeoutMs: number, + order?: FindOptionsOrder +): Promise { + return await DbCommunity.find({ + where: [ + { + authenticatedAt: Not(IsNull()), + federatedCommunities: { + verifiedAt: MoreThanOrEqual(new Date(Date.now() - authenticationTimeoutMs)) + } + }, + { foreign: false }, + ], + order, + }) +} \ No newline at end of file diff --git a/database/src/queries/pendingTransactions.test.ts b/database/src/queries/pendingTransactions.test.ts index 72deaac71..c59c312e4 100644 --- a/database/src/queries/pendingTransactions.test.ts +++ b/database/src/queries/pendingTransactions.test.ts @@ -14,7 +14,7 @@ import { peterLustig } from '../seeds/users/peter-lustig' import { bobBaumeister } from '../seeds/users/bob-baumeister' import { garrickOllivander } from '../seeds/users/garrick-ollivander' import { describe, expect, it, beforeAll, afterAll } from 'vitest' -import { createCommunity } from '../seeds/homeCommunity' +import { createCommunity } from '../seeds/community' import { v4 as uuidv4 } from 'uuid' import Decimal from 'decimal.js-light' diff --git a/database/src/queries/user.test.ts b/database/src/queries/user.test.ts index 8cb95e0ac..873ca7a2b 100644 --- a/database/src/queries/user.test.ts +++ b/database/src/queries/user.test.ts @@ -4,7 +4,7 @@ import { aliasExists, findUserByIdentifier } from './user' import { userFactory } from '../seeds/factory/user' import { bibiBloxberg } from '../seeds/users/bibi-bloxberg' import { describe, expect, it, beforeAll, afterAll, beforeEach, } from 'vitest' -import { createCommunity } from '../seeds/homeCommunity' +import { createCommunity } from '../seeds/community' import { peterLustig } from '../seeds/users/peter-lustig' import { bobBaumeister } from '../seeds/users/bob-baumeister' import { getLogger, printLogs, clearLogs } from '../../../config-schema/test/testSetup.vitest' diff --git a/database/src/queries/user.ts b/database/src/queries/user.ts index 2cb0eaaee..d7083e8aa 100644 --- a/database/src/queries/user.ts +++ b/database/src/queries/user.ts @@ -1,9 +1,8 @@ import { Raw } from 'typeorm' -import { Community, User as DbUser, UserContact as DbUserContact } from '../entity' -import { FindOptionsWhere } from 'typeorm' -import { aliasSchema, emailSchema, uuidv4Schema, urlSchema } from 'shared' +import { User as DbUser, UserContact as DbUserContact } from '../entity' +import { aliasSchema, emailSchema, uuidv4Schema } from 'shared' import { getLogger } from 'log4js' -import { LOG4JS_QUERIES_CATEGORY_NAME } from './index' +import { findWithCommunityIdentifier, LOG4JS_QUERIES_CATEGORY_NAME } from './index' export async function aliasExists(alias: string): Promise { const user = await DbUser.findOne({ @@ -22,11 +21,9 @@ export const findUserByIdentifier = async ( identifier: string, communityIdentifier?: string, ): Promise => { - const communityWhere: FindOptionsWhere = urlSchema.safeParse(communityIdentifier).success - ? { url: communityIdentifier } - : uuidv4Schema.safeParse(communityIdentifier).success - ? { communityUuid: communityIdentifier } - : { name: communityIdentifier } + const communityWhere = communityIdentifier + ? findWithCommunityIdentifier(communityIdentifier) + : undefined if (uuidv4Schema.safeParse(identifier).success) { return DbUser.findOne({ diff --git a/database/src/seeds/community.ts b/database/src/seeds/community.ts new file mode 100644 index 000000000..4db872398 --- /dev/null +++ b/database/src/seeds/community.ts @@ -0,0 +1,42 @@ +import { Community, FederatedCommunity } from '../entity' +import { randomBytes } from 'node:crypto' +import { v4 as uuidv4 } from 'uuid' + +export async function createCommunity(foreign: boolean, save: boolean = true): Promise { + const community = new Community() + community.publicKey = randomBytes(32) + community.communityUuid = uuidv4() + community.name = 'HomeCommunity-name' + community.creationDate = new Date() + + if(foreign) { + community.foreign = true + community.name = 'ForeignCommunity-name' + community.description = 'ForeignCommunity-description' + community.url = `http://foreign-${Math.random()}/api` + community.authenticatedAt = new Date() + } else { + community.foreign = false + // todo: generate valid public/private key pair (ed25519) + community.privateKey = randomBytes(64) + community.name = 'HomeCommunity-name' + community.description = 'HomeCommunity-description' + community.url = 'http://localhost/api' + } + return save ? await community.save() : community +} + +export async function createVerifiedFederatedCommunity( + apiVersion: string, + verifiedBeforeMs: number, + community: Community, + save: boolean = true +): Promise { + const federatedCommunity = new FederatedCommunity() + federatedCommunity.apiVersion = apiVersion + federatedCommunity.endPoint = community.url + federatedCommunity.publicKey = community.publicKey + federatedCommunity.community = community + federatedCommunity.verifiedAt = new Date(Date.now() - verifiedBeforeMs) + return save ? await federatedCommunity.save() : federatedCommunity +} diff --git a/database/src/seeds/homeCommunity.ts b/database/src/seeds/homeCommunity.ts deleted file mode 100644 index d76ee0b98..000000000 --- a/database/src/seeds/homeCommunity.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Community } from '../entity' -import { randomBytes } from 'node:crypto' -import { v4 as uuidv4 } from 'uuid' - -export async function createCommunity(foreign: boolean): Promise { - const homeCom = new Community() - homeCom.publicKey = randomBytes(32) - homeCom.communityUuid = uuidv4() - homeCom.authenticatedAt = new Date() - homeCom.name = 'HomeCommunity-name' - homeCom.creationDate = new Date() - - if(foreign) { - homeCom.foreign = true - homeCom.name = 'ForeignCommunity-name' - homeCom.description = 'ForeignCommunity-description' - homeCom.url = 'http://foreign/api' - } else { - homeCom.foreign = false - homeCom.privateKey = randomBytes(64) - homeCom.name = 'HomeCommunity-name' - homeCom.description = 'HomeCommunity-description' - homeCom.url = 'http://localhost/api' - } - return await homeCom.save() -} diff --git a/frontend/src/components/CommunitySwitch.vue b/frontend/src/components/CommunitySwitch.vue index b081f5d93..e0ef393d1 100644 --- a/frontend/src/components/CommunitySwitch.vue +++ b/frontend/src/components/CommunitySwitch.vue @@ -22,10 +22,10 @@