Merge branch 'master' into dlt_transmit_to_iota

This commit is contained in:
einhornimmond 2024-02-12 18:10:18 +01:00 committed by GitHub
commit 3dcafa6606
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
54 changed files with 1294 additions and 39 deletions

View File

@ -4,8 +4,28 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [2.2.0](https://github.com/gradido/gradido/compare/2.1.1...2.2.0)
- feat(frontend): update news text [`#3279`](https://github.com/gradido/gradido/pull/3279)
- feat(frontend): use params instead of query for send/identifier route [`#3277`](https://github.com/gradido/gradido/pull/3277)
- fix(other): deployment bugfixes [`#3276`](https://github.com/gradido/gradido/pull/3276)
- refactor(other): federation optimize logging, fix bug [`#3272`](https://github.com/gradido/gradido/pull/3272)
- feat(other): request limit [`#3274`](https://github.com/gradido/gradido/pull/3274)
- feat(dlt): logging views [`#3270`](https://github.com/gradido/gradido/pull/3270)
- refactor(other): hetzner cloud deploy, refactor .env [`#3267`](https://github.com/gradido/gradido/pull/3267)
- refactor(dlt): dlt connector try out dci [`#3223`](https://github.com/gradido/gradido/pull/3223)
- feat(backend): fill linked_user_gradido_id and linked_user_name for creation transactions [`#3268`](https://github.com/gradido/gradido/pull/3268)
- feat(frontend): use day for contribution dates [`#3269`](https://github.com/gradido/gradido/pull/3269)
- feat(backend): fill linked_user_id for creation transactions [`#3266`](https://github.com/gradido/gradido/pull/3266)
- docs(other): 3258 feature create gms usecase docu [`#3260`](https://github.com/gradido/gradido/pull/3260)
- fix(frontend): update moderatorChangedMemo [`#3259`](https://github.com/gradido/gradido/pull/3259)
- chore(other): change filename date-pattern and stop all modules with db-write-access [`#3245`](https://github.com/gradido/gradido/pull/3245)
#### [2.1.1](https://github.com/gradido/gradido/compare/2.0.1...2.1.1)
> 1 December 2023
- chore(release): v2.1.1 [`#3257`](https://github.com/gradido/gradido/pull/3257)
- feat(admin): wiedervorlage v2 [`#3255`](https://github.com/gradido/gradido/pull/3255)
- feat(admin): resubmission [`#3252`](https://github.com/gradido/gradido/pull/3252)
- feat(backend): grant moderator right to edit contribution memo [`#3233`](https://github.com/gradido/gradido/pull/3233)

View File

@ -3,7 +3,7 @@
"description": "Administraion Interface for Gradido",
"main": "index.js",
"author": "Moriz Wahl",
"version": "2.1.1",
"version": "2.2.0",
"license": "Apache-2.0",
"private": false,
"scripts": {

View File

@ -63,4 +63,10 @@ WEBHOOK_ELOPAGE_SECRET=secret
# Federation
FEDERATION_VALIDATE_COMMUNITY_TIMER=60000
FEDERATION_XCOM_SENDCOINS_ENABLED=false
FEDERATION_XCOM_SENDCOINS_ENABLED=false
# GMS
# GMS_ACTIVE=true
# Coordinates of Illuminz test instance
#GMS_URL=http://54.176.169.179:3071
GMS_URL=http://localhost:4044/

View File

@ -54,7 +54,7 @@ EMAIL_LINK_VERIFICATION_PATH=$EMAIL_LINK_VERIFICATION_PATH
EMAIL_LINK_SETPASSWORD_PATH=$EMAIL_LINK_SETPASSWORD_PATH
EMAIL_LINK_FORGOTPASSWORD_PATH=$EMAIL_LINK_FORGOTPASSWORD_PATH
EMAIL_LINK_OVERVIEW_PATH=$EMAIL_LINK_OVERVIEW_PATH
EMAIL_CODE_VALID_TIME=$EMAIL_CODE_VALID_TIME_PATH
EMAIL_CODE_VALID_TIME=$EMAIL_CODE_VALID_TIME
EMAIL_CODE_REQUEST_TIME=$EMAIL_CODE_REQUEST_TIME
# Webhook
@ -62,4 +62,8 @@ WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET
# Federation
FEDERATION_VALIDATE_COMMUNITY_TIMER=$FEDERATION_VALIDATE_COMMUNITY_TIMER
FEDERATION_XCOM_SENDCOINS_ENABLED=$FEDERATION_XCOM_SENDCOINS_ENABLED
FEDERATION_XCOM_SENDCOINS_ENABLED=$FEDERATION_XCOM_SENDCOINS_ENABLED
# GMS
GMS_ACTIVE=$GMS_ACTIVE
GMS_URL=$GMS_URL

View File

@ -1,6 +1,6 @@
{
"name": "gradido-backend",
"version": "2.1.1",
"version": "2.2.0",
"description": "Gradido unified backend providing an API-Service for Gradido Transactions",
"main": "src/index.ts",
"repository": "https://github.com/gradido/gradido/backend",
@ -16,6 +16,8 @@
"test": "cross-env TZ=UTC NODE_ENV=development jest --runInBand --forceExit --detectOpenHandles",
"seed": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/seeds/index.ts",
"klicktipp": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/util/executeKlicktipp.ts",
"gmsusers": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/seeds/gmsUsers.ts",
"gmsuserList": "cross-env TZ=UTC NODE_ENV=development ts-node -r tsconfig-paths/register src/seeds/gmsUserList.ts",
"locales": "scripts/sort.sh"
},
"dependencies": {

View File

@ -0,0 +1,146 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import axios from 'axios'
import { CONFIG } from '@/config'
import { LogError } from '@/server/LogError'
import { backendLogger as logger } from '@/server/logger'
import { GmsUser } from './model/GmsUser'
/*
export async function communityList(): Promise<GmsCommunity[] | string | undefined> {
const baseUrl = CONFIG.GMS_URL.endsWith('/') ? CONFIG.GMS_URL : CONFIG.GMS_URL.concat('/')
const service = 'community/list?page=1&perPage=20'
const config = {
headers: {
accept: 'application/json',
language: 'en',
timezone: 'UTC',
connection: 'keep-alive',
authorization:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiVTJGc2RHVmtYMThuNzllbGJscThDbmxxZ0I2SGxicTZuajlpM2lmV3BTc3pHZFRtOFVTQjJZNWY2bG56elhuSUF0SEwvYVBWdE1uMjA3bnNtWDQ0M21xWVFyd0xJMklHNGtpRkZ3U2FKbVJwRk9VZXNDMXIyRGlta3VLMklwN1lYRTU0c2MzVmlScmMzaHE3djlFNkRabk4xeVMrU1QwRWVZRFI5c09pTDJCdmg4a05DNUc5NTdoZUJzeWlRbXcrNFFmMXFuUk5SNXpWdXhtZEE2WUUrT3hlcS85Y0d6NURyTmhoaHM3MTJZTFcvTmprZGNwdU55dUgxeWxhNEhJZyIsImlhdCI6MTcwMDUxMDg4OX0.WhtNGZc9A_hUfh8CcPjr44kWQWMkKJ7hlYXELOd3yy4',
},
}
try {
const result = await axios.get(baseUrl.concat(service), config)
logger.debug('GET-Response of community/list:', result)
if (result.status !== 200) {
throw new LogError('HTTP Status Error in community/list:', result.status, result.statusText)
}
logger.debug('responseData:', result.data.responseData.data)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
// const gmsCom = JSON.parse(result.data.responseData.data)
// logger.debug('gmsCom:', gmsCom)
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return result.data.responseData.data
} catch (error: any) {
logger.error('Error in Get community/list:', error)
const errMsg: string = error.message
return errMsg
}
}
export async function userList(): Promise<GmsUser[] | string | undefined> {
const baseUrl = CONFIG.GMS_URL.endsWith('/') ? CONFIG.GMS_URL : CONFIG.GMS_URL.concat('/')
const service = 'community-user/list?page=1&perPage=20'
const config = {
headers: {
accept: 'application/json',
language: 'en',
timezone: 'UTC',
connection: 'keep-alive',
authorization:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiVTJGc2RHVmtYMThuNzllbGJscThDbmxxZ0I2SGxicTZuajlpM2lmV3BTc3pHZFRtOFVTQjJZNWY2bG56elhuSUF0SEwvYVBWdE1uMjA3bnNtWDQ0M21xWVFyd0xJMklHNGtpRkZ3U2FKbVJwRk9VZXNDMXIyRGlta3VLMklwN1lYRTU0c2MzVmlScmMzaHE3djlFNkRabk4xeVMrU1QwRWVZRFI5c09pTDJCdmg4a05DNUc5NTdoZUJzeWlRbXcrNFFmMXFuUk5SNXpWdXhtZEE2WUUrT3hlcS85Y0d6NURyTmhoaHM3MTJZTFcvTmprZGNwdU55dUgxeWxhNEhJZyIsImlhdCI6MTcwMDUxMDg4OX0.WhtNGZc9A_hUfh8CcPjr44kWQWMkKJ7hlYXELOd3yy4',
},
}
try {
const result = await axios.get(baseUrl.concat(service), config)
logger.debug('GET-Response of community/list:', result)
if (result.status !== 200) {
throw new LogError(
'HTTP Status Error in community-user/list:',
result.status,
result.statusText,
)
}
logger.debug('responseData:', result.data.responseData.data)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
// const gmsUser = JSON.parse(result.data.responseData.data)
// logger.debug('gmsUser:', gmsUser)
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return result.data.responseData.data
} catch (error: any) {
logger.error('Error in Get community-user/list:', error)
const errMsg: string = error.message
return errMsg
}
}
export async function userByUuid(uuid: string): Promise<GmsUser[] | string | undefined> {
const baseUrl = CONFIG.GMS_URL.endsWith('/') ? CONFIG.GMS_URL : CONFIG.GMS_URL.concat('/')
const service = 'community-user/list?page=1&perPage=20'
const config = {
headers: {
accept: 'application/json',
language: 'en',
timezone: 'UTC',
connection: 'keep-alive',
authorization:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiVTJGc2RHVmtYMThuNzllbGJscThDbmxxZ0I2SGxicTZuajlpM2lmV3BTc3pHZFRtOFVTQjJZNWY2bG56elhuSUF0SEwvYVBWdE1uMjA3bnNtWDQ0M21xWVFyd0xJMklHNGtpRkZ3U2FKbVJwRk9VZXNDMXIyRGlta3VLMklwN1lYRTU0c2MzVmlScmMzaHE3djlFNkRabk4xeVMrU1QwRWVZRFI5c09pTDJCdmg4a05DNUc5NTdoZUJzeWlRbXcrNFFmMXFuUk5SNXpWdXhtZEE2WUUrT3hlcS85Y0d6NURyTmhoaHM3MTJZTFcvTmprZGNwdU55dUgxeWxhNEhJZyIsImlhdCI6MTcwMDUxMDg4OX0.WhtNGZc9A_hUfh8CcPjr44kWQWMkKJ7hlYXELOd3yy4',
},
}
try {
const result = await axios.get(baseUrl.concat(service), config)
logger.debug('GET-Response of community/list:', result)
if (result.status !== 200) {
throw new LogError(
'HTTP Status Error in community-user/list:',
result.status,
result.statusText,
)
}
logger.debug('responseData:', result.data.responseData.data)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
// const gmsUser = JSON.parse(result.data.responseData.data)
// logger.debug('gmsUser:', gmsUser)
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return result.data.responseData.data
} catch (error: any) {
logger.error('Error in Get community-user/list:', error)
const errMsg: string = error.message
return errMsg
}
}
*/
export async function createGmsUser(apiKey: string, user: GmsUser): Promise<boolean> {
const baseUrl = CONFIG.GMS_URL.endsWith('/') ? CONFIG.GMS_URL : CONFIG.GMS_URL.concat('/')
const service = 'community-user'
const config = {
headers: {
accept: 'application/json',
language: 'en',
timezone: 'UTC',
connection: 'keep-alive',
authorization: apiKey,
},
}
try {
const result = await axios.post(baseUrl.concat(service), user, config)
logger.debug('POST-Response of community-user:', result)
if (result.status !== 200) {
throw new LogError('HTTP Status Error in community-user:', result.status, result.statusText)
}
logger.debug('responseData:', result.data.responseData)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
// const gmsUser = JSON.parse(result.data.responseData)
// logger.debug('gmsUser:', gmsUser)
return true
} catch (error: any) {
logger.error('Error in Get community-user:', error)
throw new LogError(error.message)
}
}

View File

@ -0,0 +1,19 @@
/*
import { GmsCommunityProfile } from './GmsCommunityProfile'
import { GmsRole } from './GmsRoles'
export class GmsCommunity {
id: number
uuid: string
communityUuid: string
email: string
countryCode: string
mobile: string
status: number
createdAt: Date
updatedAt: Date
UserProfile: unknown
communityProfile: GmsCommunityProfile
roles: GmsRole[]
}
*/

View File

@ -0,0 +1,18 @@
/*
export class GmsCommunityProfile {
name: string
location: {
type: string
coordinates: [number]
}
address: string
communityId: number
radius: number
description: string
// eslint-disable-next-line camelcase
api_key: string
communityAuthUrl: unknown
profileImage: unknown
}
*/

View File

@ -0,0 +1,8 @@
/*
export class GmsRole {
code: string
status: number
name: string
Permissions: [unknown]
}
*/

View File

@ -0,0 +1,110 @@
import { User as dbUser } from '@entity/User'
import { GmsPublishLocationType } from '@/graphql/enum/GmsPublishLocationType'
import { GmsPublishNameType } from '@/graphql/enum/GmsPublishNameType'
import { GmsPublishPhoneType } from '@/graphql/enum/GmsPublishPhoneType'
export class GmsUser {
constructor(user: dbUser) {
this.userUuid = user.gradidoID
// this.communityUuid = user.communityUuid
this.email = this.getGmsEmail(user)
this.countryCode = this.getGmsCountryCode(user)
this.mobile = this.getGmsPhone(user)
this.firstName = this.getGmsFirstName(user)
this.lastName = this.getGmsLastName(user)
this.alias = this.getGmsAlias(user)
this.type = GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM
this.location = null
}
id: number
userUuid: string
communityUuid: string
email: string | undefined
countryCode: string | undefined
mobile: string | undefined
status: number
createdAt: Date
updatedAt: Date
firstName: string | undefined
lastName: string | undefined
alias: string | undefined
type: number
address: string | undefined
city: string | undefined
state: string
country: string | undefined
zipCode: string | undefined
language: string
location: unknown
private getGmsAlias(user: dbUser): string | undefined {
if (
user.gmsAllowed &&
user.alias &&
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS
) {
return user.alias
}
}
private getGmsFirstName(user: dbUser): string | undefined {
if (
user.gmsAllowed &&
(user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_FIRST ||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_FIRST_INITIAL ||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_FULL)
) {
return user.firstName
}
if (
user.gmsAllowed &&
((!user.alias &&
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS) ||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_INITIALS)
) {
return user.firstName.substring(0, 1)
}
}
private getGmsLastName(user: dbUser): string | undefined {
if (user.gmsAllowed && user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_FULL) {
return user.lastName
}
if (
user.gmsAllowed &&
((!user.alias &&
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS) ||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_FIRST_INITIAL ||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_INITIALS)
) {
return user.lastName.substring(0, 1)
}
}
private getGmsEmail(user: dbUser): string | undefined {
if (user.gmsAllowed && user.emailContact.gmsPublishEmail) {
return user.emailContact.email
}
}
private getGmsCountryCode(user: dbUser): string | undefined {
if (
user.gmsAllowed &&
(user.emailContact.gmsPublishPhone === GmsPublishPhoneType.GMS_PUBLISH_PHONE_COUNTRY ||
user.emailContact.gmsPublishPhone === GmsPublishPhoneType.GMS_PUBLISH_PHONE_FULL)
) {
return user.emailContact.countryCode
}
}
private getGmsPhone(user: dbUser): string | undefined {
if (
user.gmsAllowed &&
user.emailContact.gmsPublishPhone === GmsPublishPhoneType.GMS_PUBLISH_PHONE_FULL
) {
return user.emailContact.phone
}
}
}

View File

@ -0,0 +1,18 @@
/*
import { Decimal } from 'decimal.js-light'
export class GmsUserAccount {
name: string
location: {
type: string
coordinates: [Decimal, Decimal]
}
address: string
radius: number
description: string
// eslint-disable-next-line camelcase
api_key: string
profileImage: unknown
}
*/

View File

@ -0,0 +1,24 @@
/*
import { Decimal } from 'decimal.js-light'
export class GmsUserProfile {
firstName: string | undefined
lastName: string | undefined
alias: string
type: number
name: string | undefined
location: {
type: string
coordinates: [Decimal, Decimal]
}
accuracy: unknown
address: string | undefined
city: string | undefined
state: string
country: string | undefined
zipCode: string | undefined
language: string
profileImage: unknown
}
*/

View File

@ -1,3 +1,9 @@
import { RIGHTS } from './RIGHTS'
export const ADMIN_RIGHTS = [RIGHTS.SET_USER_ROLE, RIGHTS.DELETE_USER, RIGHTS.UNDELETE_USER]
export const ADMIN_RIGHTS = [
RIGHTS.SET_USER_ROLE,
RIGHTS.DELETE_USER,
RIGHTS.UNDELETE_USER,
RIGHTS.COMMUNITY_UPDATE,
RIGHTS.COMMUNITY_BY_UUID,
]

View File

@ -58,4 +58,6 @@ export enum RIGHTS {
SET_USER_ROLE = 'SET_USER_ROLE',
DELETE_USER = 'DELETE_USER',
UNDELETE_USER = 'UNDELETE_USER',
COMMUNITY_BY_UUID = 'COMMUNITY_BY_UUID',
COMMUNITY_UPDATE = 'COMMUNITY_UPDATE',
}

View File

@ -12,7 +12,7 @@ Decimal.set({
})
const constants = {
DB_VERSION: '0081-user_join_community',
DB_VERSION: '0082-introduce_gms_registration',
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
LOG4JS_CONFIG: 'log4js-config.json',
// default log level on production should be info
@ -139,6 +139,12 @@ const federation = {
process.env.FEDERATION_XCOM_MAXREPEAT_REVERTSENDCOINS ?? 3,
}
const gms = {
GMS_ACTIVE: process.env.GMS_ACTIVE === 'true' || false,
// koordinates of Illuminz-instance of GMS
GMS_URL: process.env.GMS_HOST ?? 'http://localhost:4044/',
}
export const CONFIG = {
...constants,
...server,
@ -150,4 +156,5 @@ export const CONFIG = {
...loginServer,
...webhook,
...federation,
...gms,
}

View File

@ -0,0 +1,14 @@
import { IsString } from 'class-validator'
import { Field, ArgsType, InputType } from 'type-graphql'
@InputType()
@ArgsType()
export class CommunityArgs {
@Field(() => String)
@IsString()
uuid: string
@Field(() => String)
@IsString()
gmsApiKey: string
}

View File

@ -0,0 +1,12 @@
import { registerEnumType } from 'type-graphql'
export enum GmsPublishLocationType {
GMS_LOCATION_TYPE_EXACT = 0,
GMS_LOCATION_TYPE_APPROXIMATE = 1,
GMS_LOCATION_TYPE_RANDOM = 2,
}
registerEnumType(GmsPublishLocationType, {
name: 'GmsPublishLocationType', // this one is mandatory
description: 'Type of location treatment in GMS', // this one is optional
})

View File

@ -0,0 +1,14 @@
import { registerEnumType } from 'type-graphql'
export enum GmsPublishNameType {
GMS_PUBLISH_NAME_ALIAS_OR_INITALS = 0,
GMS_PUBLISH_NAME_INITIALS = 1,
GMS_PUBLISH_NAME_FIRST = 2,
GMS_PUBLISH_NAME_FIRST_INITIAL = 3,
GMS_PUBLISH_NAME_FULL = 4,
}
registerEnumType(GmsPublishNameType, {
name: 'GmsPublishNameType', // this one is mandatory
description: 'Type of name publishing', // this one is optional
})

View File

@ -0,0 +1,12 @@
import { registerEnumType } from 'type-graphql'
export enum GmsPublishPhoneType {
GMS_PUBLISH_PHONE_NOTHING = 0,
GMS_PUBLISH_PHONE_COUNTRY = 1,
GMS_PUBLISH_PHONE_FULL = 2,
}
registerEnumType(GmsPublishPhoneType, {
name: 'GmsPublishPhoneType', // this one is mandatory
description: 'Type of Phone publishing', // this one is optional
})

View File

@ -12,6 +12,7 @@ export class Community {
this.creationDate = dbCom.creationDate
this.uuid = dbCom.communityUuid
this.authenticatedAt = dbCom.authenticatedAt
this.gmsApiKey = dbCom.gmsApiKey
}
@Field(() => Int)
@ -37,4 +38,7 @@ export class Community {
@Field(() => Date, { nullable: true })
authenticatedAt: Date | null
@Field(() => String, { nullable: true })
gmsApiKey: string | null
}

View File

@ -9,21 +9,38 @@ import { Connection } from '@dbTools/typeorm'
import { Community as DbCommunity } from '@entity/Community'
import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity'
import { ApolloServerTestClient } from 'apollo-server-testing'
import { GraphQLError } from 'graphql/error/GraphQLError'
import { cleanDB, testEnvironment } from '@test/helpers'
import { logger, i18n as localization } from '@test/testSetup'
import { getCommunities, communities } from '@/seeds/graphql/queries'
import { userFactory } from '@/seeds/factory/user'
import { login, updateHomeCommunityQuery } from '@/seeds/graphql/mutations'
import { getCommunities, communitiesQuery, getCommunityByUuidQuery } from '@/seeds/graphql/queries'
import { peterLustig } from '@/seeds/users/peter-lustig'
import { getCommunityByUuid } from './util/communities'
// to do: We need a setup for the tests that closes the connection
let query: ApolloServerTestClient['query'], con: Connection
let mutate: ApolloServerTestClient['mutate'],
query: ApolloServerTestClient['query'],
con: Connection
let testEnv: {
mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query']
con: Connection
}
const peterLoginData = {
email: 'peter@lustig.de',
password: 'Aa12345_',
publisherId: 1234,
}
beforeAll(async () => {
testEnv = await testEnvironment()
testEnv = await testEnvironment(logger, localization)
mutate = testEnv.mutate
query = testEnv.query
con = testEnv.con
await DbFederatedCommunity.clear()
@ -302,7 +319,7 @@ describe('CommunityResolver', () => {
it('returns no community entry', async () => {
// const result: Community[] = await query({ query: getCommunities })
// expect(result.length).toEqual(0)
await expect(query({ query: communities })).resolves.toMatchObject({
await expect(query({ query: communitiesQuery })).resolves.toMatchObject({
data: {
communities: [],
},
@ -329,7 +346,7 @@ describe('CommunityResolver', () => {
})
it('returns 1 home-community entry', async () => {
await expect(query({ query: communities })).resolves.toMatchObject({
await expect(query({ query: communitiesQuery })).resolves.toMatchObject({
data: {
communities: [
{
@ -391,7 +408,7 @@ describe('CommunityResolver', () => {
})
it('returns 2 community entries', async () => {
await expect(query({ query: communities })).resolves.toMatchObject({
await expect(query({ query: communitiesQuery })).resolves.toMatchObject({
data: {
communities: [
{
@ -431,5 +448,129 @@ describe('CommunityResolver', () => {
})
})
})
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 })
// HomeCommunity is still created in userFactory
homeCom = await getCommunityByUuid(admin.communityUuid)
foreignCom1 = DbCommunity.create()
foreignCom1.foreign = true
foreignCom1.url = 'http://stage-2.gradido.net/api'
foreignCom1.publicKey = Buffer.from('publicKey-stage-2_Community')
foreignCom1.privateKey = Buffer.from('privateKey-stage-2_Community')
// 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('publicKey-stage-3_Community')
foreignCom2.privateKey = Buffer.from('privateKey-stage-3_Community')
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)
})
it('finds the home-community', async () => {
await expect(
query({
query: getCommunityByUuidQuery,
variables: { communityUuid: homeCom?.communityUuid },
}),
).resolves.toMatchObject({
data: {
community: {
id: homeCom?.id,
foreign: homeCom?.foreign,
name: homeCom?.name,
description: homeCom?.description,
url: homeCom?.url,
creationDate: homeCom?.creationDate?.toISOString(),
uuid: homeCom?.communityUuid,
authenticatedAt: homeCom?.authenticatedAt,
},
},
})
})
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: 'unknownUuid', gmsApiKey: 'gmsApiKey' },
}),
).toEqual(
expect.objectContaining({
errors: [new GraphQLError('HomeCommunity with uuid not found: ')],
}),
)
})
})
})
})

View File

@ -1,15 +1,16 @@
import { IsNull, Not } from '@dbTools/typeorm'
import { Community as DbCommunity } from '@entity/Community'
import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity'
import { Resolver, Query, Authorized, Arg } from 'type-graphql'
import { Resolver, Query, Authorized, Arg, Mutation, Args } from 'type-graphql'
import { CommunityArgs } from '@arg//CommunityArgs'
import { Community } from '@model/Community'
import { FederatedCommunity } from '@model/FederatedCommunity'
import { RIGHTS } from '@/auth/RIGHTS'
import { LogError } from '@/server/LogError'
import { getCommunity } from './util/communities'
import { getCommunityByUuid } from './util/communities'
@Resolver()
export class CommunityResolver {
@ -40,13 +41,41 @@ export class CommunityResolver {
return dbCommunities.map((dbCom: DbCommunity) => new Community(dbCom))
}
@Authorized([RIGHTS.COMMUNITIES])
@Authorized([RIGHTS.COMMUNITY_BY_UUID])
@Query(() => Community)
async community(@Arg('communityUuid') communityUuid: string): Promise<Community> {
const community = await getCommunity(communityUuid)
if (!community) {
const com: DbCommunity | null = await getCommunityByUuid(communityUuid)
if (!com) {
throw new LogError('community not found', communityUuid)
}
return new Community(community)
return new Community(com)
}
@Authorized([RIGHTS.COMMUNITY_UPDATE])
@Mutation(() => Community)
async updateHomeCommunity(@Args() { uuid, gmsApiKey }: CommunityArgs): Promise<Community> {
let homeCom: DbCommunity | null
let com: Community
if (uuid) {
let toUpdate = false
homeCom = await getCommunityByUuid(uuid)
if (!homeCom) {
throw new LogError('HomeCommunity with uuid not found: ', uuid)
}
if (homeCom.foreign) {
throw new LogError('Error: Only the HomeCommunity could be modified!')
}
if (homeCom.gmsApiKey !== gmsApiKey) {
homeCom.gmsApiKey = gmsApiKey
toUpdate = true
}
if (toUpdate) {
await DbCommunity.save(homeCom)
}
com = new Community(homeCom)
} else {
throw new LogError(`HomeCommunity without an uuid can't be modified!`)
}
return com
}
}

View File

@ -38,7 +38,7 @@ import { calculateBalance } from '@/util/validate'
import { virtualLinkTransaction, virtualDecayTransaction } from '@/util/virtualTransactions'
import { BalanceResolver } from './BalanceResolver'
import { getCommunity, getCommunityName, isHomeCommunity } from './util/communities'
import { getCommunityByUuid, getCommunityName, isHomeCommunity } from './util/communities'
import { findUserByIdentifier } from './util/findUserByIdentifier'
import { getLastTransaction } from './util/getLastTransaction'
import { getTransactionList } from './util/getTransactionList'
@ -452,7 +452,7 @@ export class TransactionResolver {
if (!CONFIG.FEDERATION_XCOM_SENDCOINS_ENABLED) {
throw new LogError('X-Community sendCoins disabled per configuration!')
}
const recipCom = await getCommunity(recipientCommunityIdentifier)
const recipCom = await getCommunityByUuid(recipientCommunityIdentifier)
logger.debug('recipient commuity: ', recipCom)
if (recipCom === null) {
throw new LogError(

View File

@ -177,6 +177,12 @@ describe('UserResolver', () => {
passwordEncryptionType: PasswordEncryptionType.NO_PASSWORD,
communityUuid: homeCom.communityUuid,
foreign: false,
gmsAllowed: true,
gmsPublishName: 0,
gmsPublishLocation: 2,
location: null,
gmsRegistered: false,
gmsRegisteredAt: null,
},
])
const valUUID = validateUUID(user[0].gradidoID)
@ -195,10 +201,13 @@ describe('UserResolver', () => {
emailVerificationCode: expect.any(String),
emailOptInTypeId: OptInType.EMAIL_OPT_IN_REGISTER,
emailResendCount: 0,
countryCode: null,
phone: null,
createdAt: expect.any(Date),
deletedAt: null,
updatedAt: null,
gmsPublishEmail: false,
gmsPublishPhone: 0,
})
})
})

View File

@ -71,6 +71,7 @@ import { findUserByIdentifier } from './util/findUserByIdentifier'
import { findUsers } from './util/findUsers'
import { getKlicktippState } from './util/getKlicktippState'
import { setUserRole, deleteUserRole } from './util/modifyUserRole'
import { sendUserToGms } from './util/sendUserToGms'
import { validateAlias } from './util/validateAlias'
const LANGUAGES = ['de', 'en', 'es', 'fr', 'nl']
@ -361,6 +362,18 @@ export class UserResolver {
} else {
await EVENT_USER_REGISTER(dbUser)
}
if (!CONFIG.GMS_ACTIVE) {
logger.info('GMS deactivated per configuration! New user is not published to GMS.')
} else {
try {
if (dbUser.gmsAllowed && !dbUser.gmsRegistered) {
await sendUserToGms(dbUser, homeCom)
}
} catch (err) {
logger.error('Error publishing new created user to GMS:', err)
}
}
return new User(dbUser)
}

View File

@ -58,7 +58,7 @@ export async function getCommunityName(communityIdentifier: string): Promise<str
}
}
export async function getCommunity(communityUuid: string): Promise<DbCommunity | null> {
export async function getCommunityByUuid(communityUuid: string): Promise<DbCommunity | null> {
return await DbCommunity.findOne({
where: [{ communityUuid }],
})

View File

@ -0,0 +1,27 @@
import { Community as DbCommunity } from '@entity/Community'
import { User as DbUser } from '@entity/User'
import { createGmsUser } from '@/apis/gms/GmsClient'
import { GmsUser } from '@/apis/gms/model/GmsUser'
import { LogError } from '@/server/LogError'
import { backendLogger as logger } from '@/server/logger'
export async function sendUserToGms(user: DbUser, homeCom: DbCommunity): Promise<void> {
if (homeCom.gmsApiKey === null) {
throw new LogError('HomeCommunity needs GMS-ApiKey to publish user data to GMS.')
}
logger.debug('User send to GMS:', user)
const gmsUser = new GmsUser(user)
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
if (await createGmsUser(homeCom.gmsApiKey, gmsUser)) {
logger.debug('GMS user published successfully:', gmsUser)
user.gmsRegistered = true
user.gmsRegisteredAt = new Date()
await DbUser.save(user)
logger.debug('mark user as gms published:', user)
}
} catch (err) {
logger.warn('publishing user fails with ', err)
}
}

View File

@ -0,0 +1,60 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-return */
import { entities } from '@entity/index'
// import { createTestClient } from 'apollo-server-testing'
import { CONFIG } from '@/config'
import { createServer } from '@/server/createServer'
import { backendLogger as logger } from '@/server/logger'
CONFIG.EMAIL = false
const context = {
token: '',
setHeaders: {
push: (value: { key: string; value: string }): void => {
context.token = value.value
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
forEach: (): void => {},
},
clientTimezoneOffset: 0,
}
export const cleanDB = async () => {
// this only works as long we do not have foreign key constraints
for (const entity of entities) {
await resetEntity(entity)
}
}
const resetEntity = async (entity: any) => {
const items = await entity.find({ withDeleted: true })
if (items.length > 0) {
const ids = items.map((e: any) => e.id)
await entity.delete(ids)
}
}
const run = async () => {
const server = await createServer(context)
// const seedClient = createTestClient(server.apollo)
const { con } = server
// test GMS-Api Client
try {
// const gmsComArray = await communityList()
// logger.debug('GMS-Community-List:', gmsComArray)
// const gmsUserArray = await userList()
// logger.debug('GMS-Community-User-List:', gmsUserArray)
} catch (err) {
logger.error('Error in GMS-API:', err)
}
await con.close()
}
void run()

View File

@ -0,0 +1,102 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-return */
import { entities } from '@entity/index'
import { User as DbUser } from '@entity/User'
// import { createTestClient } from 'apollo-server-testing'
// import { createGmsUser } from '@/apis/gms/GmsClient'
// import { GmsUser } from '@/apis/gms/model/GmsUser'
import { CONFIG } from '@/config'
import { getHomeCommunity } from '@/graphql/resolver/util/communities'
import { sendUserToGms } from '@/graphql/resolver/util/sendUserToGms'
import { createServer } from '@/server/createServer'
import { LogError } from '@/server/LogError'
import { backendLogger as logger } from '@/server/logger'
CONFIG.EMAIL = false
const context = {
token: '',
setHeaders: {
push: (value: { key: string; value: string }): void => {
context.token = value.value
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
forEach: (): void => {},
},
clientTimezoneOffset: 0,
}
export const cleanDB = async () => {
// this only works as long we do not have foreign key constraints
for (const entity of entities) {
await resetEntity(entity)
}
}
const resetEntity = async (entity: any) => {
const items = await entity.find({ withDeleted: true })
if (items.length > 0) {
const ids = items.map((e: any) => e.id)
await entity.delete(ids)
}
}
const run = async () => {
const server = await createServer(context)
// const seedClient = createTestClient(server.apollo)
const { con } = server
const homeCom = await getHomeCommunity()
if (homeCom.gmsApiKey === null) {
throw new LogError('HomeCommunity needs GMS-ApiKey to publish user data to GMS.')
}
// read the ids of all local users, which are still not gms registered
const userIds = await DbUser.createQueryBuilder()
.select('id')
.where({ foreign: false })
.andWhere('deleted_at is null')
.andWhere({ gmsRegistered: false })
.getRawMany()
logger.debug('userIds:', userIds)
for (const idStr of userIds) {
logger.debug('Id:', idStr.id)
const user = await DbUser.findOne({
where: { id: idStr.id },
relations: ['emailContact'],
})
if (user) {
logger.debug('found local User:', user)
if (user.gmsAllowed) {
await sendUserToGms(user, homeCom)
/*
const gmsUser = new GmsUser(user)
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
if (await createGmsUser(homeCom.gmsApiKey, gmsUser)) {
logger.debug('GMS user published successfully:', gmsUser)
user.gmsRegistered = true
user.gmsRegisteredAt = new Date()
await DbUser.save(user)
logger.debug('mark user as gms published:', user)
}
} catch (err) {
logger.warn('publishing user fails with ', err)
}
*/
} else {
logger.debug('GMS-Publishing not allowed by user settings:', user)
}
}
}
logger.info('##gms## publishing all local users successful...')
await con.close()
}
void run()

View File

@ -354,3 +354,19 @@ export const logout = gql`
logout
}
`
export const updateHomeCommunityQuery = gql`
mutation ($uuid: String!, $gmsApiKey: String!) {
updateHomeCommunity(uuid: $uuid, gmsApiKey: $gmsApiKey) {
id
foreign
name
description
url
creationDate
uuid
authenticatedAt
gmsApiKey
}
}
`

View File

@ -118,7 +118,7 @@ export const listGDTEntriesQuery = gql`
}
`
export const communities = gql`
export const communitiesQuery = gql`
query {
communities {
id
@ -129,6 +129,23 @@ export const communities = gql`
creationDate
uuid
authenticatedAt
gmsApiKey
}
}
`
export const getCommunityByUuidQuery = gql`
query ($communityUuid: String!) {
community(communityUuid: $communityUuid) {
id
foreign
name
description
url
creationDate
uuid
authenticatedAt
gmsApiKey
}
}
`

View File

@ -79,6 +79,8 @@ export const createServer = async (
*/
})
app.use(limiter)
// because of nginx proxy, needed for limiter
app.set('trust proxy', 1)
// bodyparser json
app.use(json())

View File

@ -51,6 +51,12 @@ const communityDbUser: dbUser = {
foreign: false,
communityUuid: '55555555-4444-4333-2222-11111111',
community: null,
gmsPublishName: 0,
gmsAllowed: false,
location: null,
gmsPublishLocation: 2,
gmsRegistered: false,
gmsRegisteredAt: null,
}
const communityUser = new User(communityDbUser)

View File

@ -0,0 +1,73 @@
import {
BaseEntity,
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
OneToMany,
JoinColumn,
} from 'typeorm'
import { User } from '../User'
@Entity('communities')
export class Community extends BaseEntity {
@PrimaryGeneratedColumn('increment', { unsigned: true })
id: number
@Column({ name: 'foreign', type: 'bool', nullable: false, default: true })
foreign: boolean
@Column({ name: 'url', length: 255, nullable: false })
url: string
@Column({ name: 'public_key', type: 'binary', length: 32, nullable: false })
publicKey: Buffer
@Column({ name: 'private_key', type: 'binary', length: 64, nullable: true })
privateKey: Buffer | null
@Column({
name: 'community_uuid',
type: 'char',
length: 36,
nullable: true,
collation: 'utf8mb4_unicode_ci',
})
communityUuid: string | null
@Column({ name: 'authenticated_at', type: 'datetime', nullable: true })
authenticatedAt: Date | null
@Column({ name: 'name', type: 'varchar', length: 40, nullable: true })
name: string | null
@Column({ name: 'description', type: 'varchar', length: 255, nullable: true })
description: string | null
@CreateDateColumn({ name: 'creation_date', type: 'datetime', nullable: true })
creationDate: Date | null
@Column({ name: 'gms_api_key', type: 'varchar', length: 512, nullable: true, default: null })
gmsApiKey: string | null
@CreateDateColumn({
name: 'created_at',
type: 'datetime',
default: () => 'CURRENT_TIMESTAMP(3)',
nullable: false,
})
createdAt: Date
@UpdateDateColumn({
name: 'updated_at',
type: 'datetime',
onUpdate: 'CURRENT_TIMESTAMP(3)',
nullable: true,
})
updatedAt: Date | null
@OneToMany(() => User, (user) => user.community)
@JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' })
users: User[]
}

View File

@ -0,0 +1,163 @@
import {
BaseEntity,
Entity,
PrimaryGeneratedColumn,
Column,
DeleteDateColumn,
OneToMany,
JoinColumn,
OneToOne,
Geometry,
ManyToOne,
} from 'typeorm'
import { Contribution } from '../Contribution'
import { ContributionMessage } from '../ContributionMessage'
import { UserContact } from '../UserContact'
import { UserRole } from '../UserRole'
import { Community } from '../Community'
@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' })
export class User extends BaseEntity {
@PrimaryGeneratedColumn('increment', { unsigned: true })
id: number
@Column({ type: 'bool', default: false })
foreign: boolean
@Column({
name: 'gradido_id',
length: 36,
nullable: false,
collation: 'utf8mb4_unicode_ci',
})
gradidoID: string
@Column({
name: 'community_uuid',
type: 'char',
length: 36,
nullable: true,
collation: 'utf8mb4_unicode_ci',
})
communityUuid: string
@ManyToOne(() => Community, (community) => community.users)
@JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' })
community: Community | null
@Column({
name: 'alias',
length: 20,
nullable: true,
default: null,
collation: 'utf8mb4_unicode_ci',
})
alias: string
@OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user)
@JoinColumn({ name: 'email_id' })
emailContact: UserContact
@Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null })
emailId: number | null
@Column({
name: 'first_name',
length: 255,
nullable: true,
default: null,
collation: 'utf8mb4_unicode_ci',
})
firstName: string
@Column({
name: 'last_name',
length: 255,
nullable: true,
default: null,
collation: 'utf8mb4_unicode_ci',
})
lastName: string
@Column({ name: 'gms_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 })
gmsPublishName: number
@Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false })
createdAt: Date
@DeleteDateColumn({ name: 'deleted_at', nullable: true })
deletedAt: Date | null
@Column({ type: 'bigint', default: 0, unsigned: true })
password: BigInt
@Column({
name: 'password_encryption_type',
type: 'int',
unsigned: true,
nullable: false,
default: 0,
})
passwordEncryptionType: number
@Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false })
language: string
@Column({ type: 'bool', default: false })
hideAmountGDD: boolean
@Column({ type: 'bool', default: false })
hideAmountGDT: boolean
@OneToMany(() => UserRole, (userRole) => userRole.user)
@JoinColumn({ name: 'user_id' })
userRoles: UserRole[]
@Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null })
referrerId?: number | null
@Column({
name: 'contribution_link_id',
type: 'int',
unsigned: true,
nullable: true,
default: null,
})
contributionLinkId?: number | null
@Column({ name: 'publisher_id', default: 0 })
publisherId: number
@Column({ name: 'gms_allowed', type: 'bool', default: true })
gmsAllowed: boolean
@Column({ name: 'location', type: 'geometry', default: null, nullable: true })
location: Geometry | null
@Column({
name: 'gms_publish_location',
type: 'int',
unsigned: true,
nullable: false,
default: 2,
})
gmsPublishLocation: number
@Column({ name: 'gms_registered', type: 'bool', default: false })
gmsRegistered: boolean
@Column({ name: 'gms_registered_at', type: 'datetime', default: null, nullable: true })
gmsRegisteredAt: Date | null
@OneToMany(() => Contribution, (contribution) => contribution.user)
@JoinColumn({ name: 'user_id' })
contributions?: Contribution[]
@OneToMany(() => ContributionMessage, (message) => message.user)
@JoinColumn({ name: 'user_id' })
messages?: ContributionMessage[]
@OneToMany(() => UserContact, (userContact: UserContact) => userContact.user)
@JoinColumn({ name: 'user_id' })
userContacts?: UserContact[]
}

View File

@ -0,0 +1,78 @@
import {
BaseEntity,
Entity,
PrimaryGeneratedColumn,
Column,
DeleteDateColumn,
OneToOne,
CreateDateColumn,
UpdateDateColumn,
} from 'typeorm'
import { User } from '../User'
@Entity('user_contacts', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' })
export class UserContact extends BaseEntity {
@PrimaryGeneratedColumn('increment', { unsigned: true })
id: number
@Column({
name: 'type',
length: 100,
nullable: true,
default: null,
collation: 'utf8mb4_unicode_ci',
})
type: string
@OneToOne(() => User, (user) => user.emailContact)
user: User
@Column({ name: 'user_id', type: 'int', unsigned: true, nullable: false })
userId: number
@Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' })
email: string
@Column({ name: 'gms_publish_email', type: 'bool', nullable: false, default: false })
gmsPublishEmail: boolean
@Column({ name: 'email_verification_code', type: 'bigint', unsigned: true, unique: true })
emailVerificationCode: string
@Column({ name: 'email_opt_in_type_id' })
emailOptInTypeId: number
@Column({ name: 'email_resend_count' })
emailResendCount: number
@Column({ name: 'email_checked', type: 'bool', nullable: false, default: false })
emailChecked: boolean
@Column({
name: 'country_code',
length: 255,
unique: false,
nullable: true,
collation: 'utf8mb4_unicode_ci',
})
countryCode: string
@Column({ length: 255, unique: false, nullable: true, collation: 'utf8mb4_unicode_ci' })
phone: string
@Column({ name: 'gms_publish_phone', type: 'int', unsigned: true, nullable: false, default: 0 })
gmsPublishPhone: number
@CreateDateColumn({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false })
createdAt: Date
@UpdateDateColumn({
name: 'updated_at',
nullable: true,
onUpdate: 'CURRENT_TIMESTAMP(3)',
})
updatedAt: Date | null
@DeleteDateColumn({ name: 'deleted_at', nullable: true })
deletedAt: Date | null
}

View File

@ -1 +1 @@
export { Community } from './0081-user_join_community/Community'
export { Community } from './0082-introduce_gms_registration/Community'

View File

@ -1 +1 @@
export { User } from './0081-user_join_community/User'
export { User } from './0082-introduce_gms_registration/User'

View File

@ -1 +1 @@
export { UserContact } from './0057-clear_old_password_junk/UserContact'
export { UserContact } from './0082-introduce_gms_registration/UserContact'

View File

@ -0,0 +1,54 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable @typescript-eslint/no-explicit-any */
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
await queryFn(
'ALTER TABLE `users` MODIFY COLUMN `foreign` tinyint(1) NOT NULL DEFAULT 0 AFTER `id`;',
)
await queryFn(
'ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `gms_publish_name` int unsigned NOT NULL DEFAULT 0 AFTER `last_name`;', // COMMENT '0:alias if exists or initials only , 1:initials only, 2:firstName only, 3:firstName + Initial of LastName, 4:fullName'
)
await queryFn(
'ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `gms_allowed` tinyint(1) NOT NULL DEFAULT 1;',
)
await queryFn(
'ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `location` geometry DEFAULT NULL NULL AFTER `gms_allowed`;',
)
await queryFn(
'ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `gms_publish_location` int unsigned NOT NULL DEFAULT 2 AFTER `location`;', // COMMENT '0:exact, 1:approximate, 2:random'
)
await queryFn(
'ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `gms_registered` tinyint(1) NOT NULL DEFAULT 0;',
)
await queryFn(
'ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `gms_registered_at` datetime(3) DEFAULT NULL NULL;',
)
await queryFn(
'ALTER TABLE `user_contacts` ADD COLUMN IF NOT EXISTS `gms_publish_email` tinyint(1) NOT NULL DEFAULT 0 AFTER `email_checked`;', // COMMENT '0:nothing, 1:email'
)
await queryFn(
'ALTER TABLE `user_contacts` ADD COLUMN IF NOT EXISTS `country_code` varchar(255) DEFAULT NULL NULL AFTER `gms_publish_email`;',
)
await queryFn(
'ALTER TABLE `user_contacts` ADD COLUMN IF NOT EXISTS `gms_publish_phone` int unsigned NOT NULL DEFAULT 0 AFTER `phone`;', // COMMENT '0:nothing, 1:country_code only, 2:complet phone number'
)
await queryFn(
'ALTER TABLE `communities` ADD COLUMN IF NOT EXISTS `gms_api_key` varchar(512) DEFAULT NULL NULL AFTER `description`;',
)
}
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
await queryFn(
'ALTER TABLE `users` MODIFY COLUMN `foreign` tinyint(4) NOT NULL DEFAULT 0 AFTER `id`;',
)
await queryFn('ALTER TABLE `users` DROP COLUMN IF EXISTS `gms_publish_name`;')
await queryFn('ALTER TABLE `users` DROP COLUMN IF EXISTS `gms_allowed`;')
await queryFn('ALTER TABLE `users` DROP COLUMN IF EXISTS `location`;')
await queryFn('ALTER TABLE `users` DROP COLUMN IF EXISTS `gms_publish_location`;')
await queryFn('ALTER TABLE `users` DROP COLUMN IF EXISTS `gms_registered`;')
await queryFn('ALTER TABLE `users` DROP COLUMN IF EXISTS `gms_registered_at`;')
await queryFn('ALTER TABLE `user_contacts` DROP COLUMN IF EXISTS `gms_publish_email`;')
await queryFn('ALTER TABLE `user_contacts` DROP COLUMN IF EXISTS `country_code`;')
await queryFn('ALTER TABLE `user_contacts` DROP COLUMN IF EXISTS `gms_publish_phone`;')
await queryFn('ALTER TABLE `communities` DROP COLUMN IF EXISTS `gms_api_key`;')
}

View File

@ -1,6 +1,6 @@
{
"name": "gradido-database",
"version": "2.1.1",
"version": "2.2.0",
"description": "Gradido Database Tool to execute database migrations",
"main": "src/index.ts",
"repository": "https://github.com/gradido/gradido/database",

View File

@ -30,7 +30,6 @@ FRONTEND_CONFIG_VERSION=v5.2024-01-08
ADMIN_CONFIG_VERSION=v2.2024-01-04
FEDERATION_CONFIG_VERSION=v2.2023-08-24
FEDERATION_DHT_CONFIG_VERSION=v4.2024-01-17
FEDERATION_DHT_TOPIC=GRADIDO_HUB
# Need adjustments for test system
@ -118,4 +117,11 @@ NGINX_SSL_INCLUDE=/etc/letsencrypt/options-ssl-nginx.conf
# LEGACY
NGINX_REWRITE_LEGACY_URLS=false
DEFAULT_PUBLISHER_ID=2896
WEBHOOK_ELOPAGE_SECRET=secret
WEBHOOK_ELOPAGE_SECRET=secret
# GMS
#GMS_ACTIVE=true
# Coordinates of Illuminz test instance
#GMS_URL=http://54.176.169.179:3071
#GMS_URL=http://localhost:4044/

View File

@ -1,5 +1,9 @@
#!/bin/bash
# check for parameter
if [ -z "$1" ]; then
echo "Usage: Please provide a branch name as the first argument."
exit 1
fi
# Find current directory & configure paths
set -o allexport
SCRIPT_PATH=$(realpath $0)
@ -80,7 +84,7 @@ pm2 delete all
pm2 save
# git
BRANCH=${1:-master}
BRANCH=$1
echo "Starting with git pull - branch:$BRANCH" >> $UPDATE_HTML
cd $PROJECT_ROOT
# TODO: this overfetches alot, but ensures we can use start.sh with tags

View File

@ -1,4 +1,9 @@
#!/bin/bash
# check for parameter
if [ -z "$1" ]; then
echo "Usage: Please provide a branch name as the first argument."
exit 1
fi
# Note: This is needed - since there is Summer-Time included in the default server Setup - UTC is REQUIRED for production data
timedatectl set-timezone UTC

View File

@ -1,6 +1,6 @@
{
"name": "gradido-dht-node",
"version": "2.1.1",
"version": "2.2.0",
"description": "Gradido dht-node module",
"main": "src/index.ts",
"repository": "https://github.com/gradido/gradido/",

View File

@ -4,7 +4,7 @@ import dotenv from 'dotenv'
dotenv.config()
const constants = {
DB_VERSION: '0081-user_join_community',
DB_VERSION: '0082-introduce_gms_registration',
LOG4JS_CONFIG: 'log4js-config.json',
// default log level on production should be info
LOG_LEVEL: process.env.LOG_LEVEL ?? 'info',

View File

@ -1,6 +1,6 @@
{
"name": "gradido-dlt-connector",
"version": "2.1.1",
"version": "2.2.0",
"description": "Gradido DLT-Connector",
"main": "src/index.ts",
"repository": "https://github.com/gradido/gradido/",

View File

@ -62,6 +62,8 @@ const createServer = async (
*/
})
app.use(limiter)
// because of nginx proxy, needed for limiter
app.set('trust proxy', 1)
await apollo.start()
app.use(

View File

@ -1,6 +1,6 @@
{
"name": "gradido-federation",
"version": "2.1.1",
"version": "2.2.0",
"description": "Gradido federation module providing Gradido-Hub-Federation and versioned API for inter community communication",
"main": "src/index.ts",
"repository": "https://github.com/gradido/gradido/federation",

View File

@ -10,7 +10,7 @@ Decimal.set({
})
const constants = {
DB_VERSION: '0081-user_join_community',
DB_VERSION: '0082-introduce_gms_registration',
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
LOG4JS_CONFIG: 'log4js-config.json',
// default log level on production should be info

View File

@ -84,6 +84,8 @@ export const createServer = async (
*/
})
app.use(limiter)
// because of nginx proxy, needed for limiter
app.set('trust proxy', 1)
// bodyparser json
app.use(express.json())

View File

@ -1,6 +1,6 @@
{
"name": "bootstrap-vue-gradido-wallet",
"version": "2.1.1",
"version": "2.2.0",
"private": true,
"scripts": {
"start": "node run/server.js",

View File

@ -1,6 +1,6 @@
{
"name": "gradido",
"version": "2.1.1",
"version": "2.2.0",
"description": "Gradido",
"main": "index.js",
"repository": "git@github.com:gradido/gradido.git",

View File

@ -38,4 +38,4 @@ yarn version --no-git-tag-version --no-commit-hooks --no-commit --new-version ${
# generate changelog
cd ${PROJECT_DIR}
auto-changelog --commit-limit 0 --latest-version ${VERSION}
./node_modules/.bin/auto-changelog --commit-limit 0 --latest-version ${VERSION}