mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
Merge remote-tracking branch 'origin/master' into 3522-feature-introduce-security-in-disbursement-handshake
This commit is contained in:
commit
0a23e11af3
11
.github/workflows/publish.yml
vendored
11
.github/workflows/publish.yml
vendored
@ -10,6 +10,7 @@ jobs:
|
||||
# JOB: DOCKER BUILD PRODUCTION FRONTEND ######################################
|
||||
##############################################################################
|
||||
build_production_frontend:
|
||||
if: startsWith(github.event.head_commit.message, 'chore(release):')
|
||||
name: Docker Build Production - Frontend
|
||||
runs-on: ubuntu-latest
|
||||
#needs: [nothing]
|
||||
@ -47,6 +48,7 @@ jobs:
|
||||
# JOB: DOCKER BUILD PRODUCTION ADMIN #########################################
|
||||
##############################################################################
|
||||
build_production_admin:
|
||||
if: startsWith(github.event.head_commit.message, 'chore(release):')
|
||||
name: Docker Build Production - Admin
|
||||
runs-on: ubuntu-latest
|
||||
#needs: [nothing]
|
||||
@ -84,6 +86,7 @@ jobs:
|
||||
# JOB: DOCKER BUILD PRODUCTION BACKEND #######################################
|
||||
##############################################################################
|
||||
build_production_backend:
|
||||
if: startsWith(github.event.head_commit.message, 'chore(release):')
|
||||
name: Docker Build Production - Backend
|
||||
runs-on: ubuntu-latest
|
||||
#needs: [nothing]
|
||||
@ -121,6 +124,7 @@ jobs:
|
||||
# JOB: DOCKER BUILD PRODUCTION DHT-NODE ######################################
|
||||
##############################################################################
|
||||
build_production_dht-node:
|
||||
if: startsWith(github.event.head_commit.message, 'chore(release):')
|
||||
name: Docker Build Production - DHT-Node
|
||||
runs-on: ubuntu-latest
|
||||
#needs: [nothing]
|
||||
@ -158,6 +162,7 @@ jobs:
|
||||
# JOB: DOCKER BUILD PRODUCTION FEDERATION ######################################
|
||||
##############################################################################
|
||||
build_production_federation:
|
||||
if: startsWith(github.event.head_commit.message, 'chore(release):')
|
||||
name: Docker Build Production - Federation
|
||||
runs-on: ubuntu-latest
|
||||
#needs: [nothing]
|
||||
@ -195,6 +200,7 @@ jobs:
|
||||
# JOB: DOCKER BUILD PRODUCTION DATABASE UP ###################################
|
||||
##############################################################################
|
||||
build_production_database_up:
|
||||
if: startsWith(github.event.head_commit.message, 'chore(release):')
|
||||
name: Docker Build Production - Database up
|
||||
runs-on: ubuntu-latest
|
||||
#needs: [nothing]
|
||||
@ -221,6 +227,7 @@ jobs:
|
||||
# JOB: DOCKER BUILD PRODUCTION NGINX #########################################
|
||||
##############################################################################
|
||||
build_production_nginx:
|
||||
if: startsWith(github.event.head_commit.message, 'chore(release):')
|
||||
name: Docker Build Production - Nginx
|
||||
runs-on: ubuntu-latest
|
||||
#needs: [nothing]
|
||||
@ -258,6 +265,7 @@ jobs:
|
||||
# JOB: UPLOAD TO DOCKERHUB ###################################################
|
||||
##############################################################################
|
||||
upload_to_dockerhub:
|
||||
if: startsWith(github.event.head_commit.message, 'chore(release):')
|
||||
name: Upload to Dockerhub
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_production_frontend, build_production_backend, build_production_database_up, build_production_nginx]
|
||||
@ -315,8 +323,6 @@ jobs:
|
||||
path: /tmp
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/database_up.tar
|
||||
- name: Load Docker Image
|
||||
run: docker load < /tmp/mariadb.tar
|
||||
- name: Download Docker Image (Nginx)
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@ -348,6 +354,7 @@ jobs:
|
||||
##############################################################################
|
||||
##############################################################################
|
||||
github_tag:
|
||||
if: startsWith(github.event.head_commit.message, 'chore(release):')
|
||||
name: Tag latest version on Github
|
||||
runs-on: ubuntu-latest
|
||||
needs: [upload_to_dockerhub]
|
||||
|
||||
2
.github/workflows/test_database.yml
vendored
2
.github/workflows/test_database.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Database | Build image
|
||||
run: docker build --target build -t "gradido/database:build" -f database/Dockerfile .
|
||||
run: docker build --target up -t "gradido/database:up" -f database/Dockerfile .
|
||||
|
||||
database_migration_test:
|
||||
if: needs.files-changed.outputs.database == 'true' || needs.files-changed.outputs.docker-compose == 'true' || needs.files-changed.outputs.mariadb == 'true' || needs.files-changed.outputs.shared == 'true'
|
||||
|
||||
43
README.md
43
README.md
@ -174,6 +174,49 @@ turbo frontend#dev backend#start admin#start --env-mode=loose
|
||||
|
||||
Tip: for local setup use a local nginx server with similar config like docker nginx [nginx.conf](./nginx/gradido.conf) but replace docker image name with localhost
|
||||
|
||||
### Testing
|
||||
This project uses a mocked `log4js` logger for tests.
|
||||
|
||||
- **clearLogs()**: Clears all collected logs. Call in `beforeEach` to start with a clean slate.
|
||||
- **printLogs()**: Prints all collected logs since the last call to clearLogs for debugging purposes.
|
||||
- Supports log levels: `trace`, `debug`, `info`, `warn`, `error`, `fatal`.
|
||||
- Logs include context and additional arguments.
|
||||
- Example:
|
||||
|
||||
```ts
|
||||
import { clearLogs, printLogs } from 'config-schema/test/testSetup'
|
||||
|
||||
beforeEach(() => {
|
||||
clearLogs()
|
||||
})
|
||||
describe('test', () => {
|
||||
it('test', () => {
|
||||
expect(functionCall()).toBe(true)
|
||||
printLogs()
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
#### Include Paths by test framework:
|
||||
- jest (backend, dht-node, federation):
|
||||
```ts
|
||||
import { clearLogs, printLogs } from 'config-schema/test/testSetup'
|
||||
```
|
||||
- vitest (frontend, admin, database):
|
||||
```ts
|
||||
import { clearLogs, printLogs } from 'config-schema/test/testSetup.vitest'
|
||||
```
|
||||
- bun (shared, core):
|
||||
```ts
|
||||
import { clearLogs, printLogs } from 'config-schema/test/testSetup.bun'
|
||||
```
|
||||
|
||||
|
||||
#### Attention!
|
||||
It isn't tested for parallel running tests yet.
|
||||
Currently Modules `frontend`, `admin`, `share` and `core` running the tests in parallel,
|
||||
`database`, `backend`, `dht-node` and `federation` are running the tests still serially.
|
||||
|
||||
### Clear
|
||||
In root folder calling `yarn clear` will clear all turbo caches, node_modules and build folders of all workspaces for a clean rebuild.
|
||||
|
||||
|
||||
@ -28,6 +28,9 @@
|
||||
<BListGroupItem>
|
||||
{{ $t('federation.publicKey') }} {{ item.publicKey }}
|
||||
</BListGroupItem>
|
||||
<BListGroupItem v-if="item.hieroTopicId && item.foreign">
|
||||
{{ $t('federation.hieroTopicId') }} {{ item.hieroTopicId }}
|
||||
</BListGroupItem>
|
||||
<BListGroupItem v-if="!item.foreign">
|
||||
<editable-group
|
||||
:allow-edit="$store.state.moderator.roles.includes('ADMIN')"
|
||||
@ -39,6 +42,10 @@
|
||||
<p style="text-wrap: nowrap">{{ $t('federation.gmsApiKey') }} </p>
|
||||
<span class="d-block" style="overflow-x: auto">{{ gmsApiKey }}</span>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<p style="text-wrap: nowrap">{{ $t('federation.hieroTopicId') }} </p>
|
||||
<span class="d-block" style="overflow-x: auto">{{ hieroTopicId }}</span>
|
||||
</div>
|
||||
<BFormGroup>
|
||||
{{ $t('federation.coordinates') }}
|
||||
<span v-if="isValidLocation">
|
||||
@ -57,6 +64,11 @@
|
||||
:label="$t('federation.gmsApiKey')"
|
||||
id-name="home-community-api-key"
|
||||
/>
|
||||
<editable-groupable-label
|
||||
v-model="hieroTopicId"
|
||||
:label="$t('federation.hieroTopicId')"
|
||||
id-name="home-community-hiero-topic-id"
|
||||
/>
|
||||
<coordinates v-model="location" />
|
||||
</template>
|
||||
</editable-group>
|
||||
@ -111,9 +123,11 @@ const { toastSuccess, toastError } = useAppToast()
|
||||
|
||||
const details = ref(false)
|
||||
const gmsApiKey = ref(item.value.gmsApiKey)
|
||||
const hieroTopicId = ref(item.value.hieroTopicId)
|
||||
const location = ref(item.value.location)
|
||||
const originalGmsApiKey = ref(item.value.gmsApiKey)
|
||||
const originalLocation = ref(item.value.location)
|
||||
const originalHieroTopicId = ref(item.value.hieroTopicId)
|
||||
|
||||
const { mutate: updateHomeCommunityMutation } = useMutation(updateHomeCommunity)
|
||||
|
||||
@ -164,6 +178,7 @@ const createdAt = computed(() => {
|
||||
|
||||
const isLocationChanged = computed(() => originalLocation.value !== location.value)
|
||||
const isGMSApiKeyChanged = computed(() => originalGmsApiKey.value !== gmsApiKey.value)
|
||||
const isHieroTopicIdChanged = computed(() => originalHieroTopicId.value !== hieroTopicId.value)
|
||||
const isValidLocation = computed(
|
||||
() => location.value && location.value.latitude && location.value.longitude,
|
||||
)
|
||||
@ -178,6 +193,7 @@ const handleUpdateHomeCommunity = async () => {
|
||||
uuid: item.value.uuid,
|
||||
gmsApiKey: gmsApiKey.value,
|
||||
location: location.value,
|
||||
hieroTopicId: hieroTopicId.value,
|
||||
})
|
||||
|
||||
if (isLocationChanged.value && isGMSApiKeyChanged.value) {
|
||||
@ -187,8 +203,12 @@ const handleUpdateHomeCommunity = async () => {
|
||||
} else if (isLocationChanged.value) {
|
||||
toastSuccess(t('federation.toast_gmsLocationUpdated'))
|
||||
}
|
||||
if (isHieroTopicIdChanged.value) {
|
||||
toastSuccess(t('federation.toast_hieroTopicIdUpdated'))
|
||||
}
|
||||
originalLocation.value = location.value
|
||||
originalGmsApiKey.value = gmsApiKey.value
|
||||
originalHieroTopicId.value = hieroTopicId.value
|
||||
} catch (error) {
|
||||
toastError(error.message)
|
||||
}
|
||||
@ -197,5 +217,6 @@ const handleUpdateHomeCommunity = async () => {
|
||||
const resetHomeCommunityEditable = () => {
|
||||
location.value = originalLocation.value
|
||||
gmsApiKey.value = originalGmsApiKey.value
|
||||
hieroTopicId.value = originalHieroTopicId.value
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -15,6 +15,7 @@ export const allCommunities = gql`
|
||||
creationDate
|
||||
createdAt
|
||||
updatedAt
|
||||
hieroTopicId
|
||||
federatedCommunities {
|
||||
id
|
||||
apiVersion
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const updateHomeCommunity = gql`
|
||||
mutation ($uuid: String!, $gmsApiKey: String, $location: Location) {
|
||||
updateHomeCommunity(uuid: $uuid, gmsApiKey: $gmsApiKey, location: $location) {
|
||||
mutation ($uuid: String!, $gmsApiKey: String, $location: Location, $hieroTopicId: String) {
|
||||
updateHomeCommunity(
|
||||
uuid: $uuid
|
||||
gmsApiKey: $gmsApiKey
|
||||
location: $location
|
||||
hieroTopicId: $hieroTopicId
|
||||
) {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,9 +96,11 @@
|
||||
"coordinates": "Koordinaten:",
|
||||
"createdAt": "Erstellt am",
|
||||
"gmsApiKey": "GMS API Key:",
|
||||
"hieroTopicId": "Hiero Topic ID:",
|
||||
"toast_gmsApiKeyAndLocationUpdated": "Der GMS Api Key und die Location wurden erfolgreich aktualisiert!",
|
||||
"toast_gmsApiKeyUpdated": "Der GMS Api Key wurde erfolgreich aktualisiert!",
|
||||
"toast_gmsLocationUpdated": "Die GMS Location wurde erfolgreich aktualisiert!",
|
||||
"toast_hieroTopicIdUpdated": "Die Hiero Topic ID wurde erfolgreich aktualisiert!",
|
||||
"gradidoInstances": "Gradido Instanzen",
|
||||
"lastAnnouncedAt": "letzte Bekanntgabe",
|
||||
"lastErrorAt": "Letzer Fehler am",
|
||||
|
||||
@ -96,9 +96,11 @@
|
||||
"coordinates": "Coordinates:",
|
||||
"createdAt": "Created At ",
|
||||
"gmsApiKey": "GMS API Key:",
|
||||
"hieroTopicId": "Hiero Topic ID:",
|
||||
"toast_gmsApiKeyAndLocationUpdated": "The GMS Api Key and the location have been successfully updated!",
|
||||
"toast_gmsApiKeyUpdated": "The GMS Api Key has been successfully updated!",
|
||||
"toast_gmsLocationUpdated": "The GMS location has been successfully updated!",
|
||||
"toast_hieroTopicIdUpdated": "The Hiero Topic ID has been successfully updated!",
|
||||
"gradidoInstances": "Gradido Instances",
|
||||
"lastAnnouncedAt": "Last Announced",
|
||||
"lastErrorAt": "last error at",
|
||||
|
||||
@ -18,4 +18,8 @@ export class EditCommunityInput {
|
||||
@Field(() => Location, { nullable: true })
|
||||
@isValidLocation()
|
||||
location?: Location | null
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
@IsString()
|
||||
hieroTopicId?: string | null
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ export class AdminCommunityView {
|
||||
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)
|
||||
}
|
||||
@ -71,6 +72,9 @@ export class AdminCommunityView {
|
||||
@Field(() => Location, { nullable: true })
|
||||
location: Location | null
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
hieroTopicId: string | null
|
||||
|
||||
@Field(() => Date, { nullable: true })
|
||||
creationDate: Date | null
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ export class Community {
|
||||
this.uuid = dbCom.communityUuid
|
||||
this.authenticatedAt = dbCom.authenticatedAt
|
||||
this.gmsApiKey = dbCom.gmsApiKey
|
||||
this.hieroTopicId = dbCom.hieroTopicId
|
||||
}
|
||||
|
||||
@Field(() => Int)
|
||||
@ -41,4 +42,7 @@ export class Community {
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
gmsApiKey: string | null
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
hieroTopicId: string | null
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ export class CommunityResolver {
|
||||
@Authorized([RIGHTS.COMMUNITY_UPDATE])
|
||||
@Mutation(() => Community)
|
||||
async updateHomeCommunity(
|
||||
@Args() { uuid, gmsApiKey, location }: EditCommunityInput,
|
||||
@Args() { uuid, gmsApiKey, location, hieroTopicId }: EditCommunityInput,
|
||||
): Promise<Community> {
|
||||
const homeCom = await getCommunityByUuid(uuid)
|
||||
if (!homeCom) {
|
||||
@ -89,11 +89,16 @@ export class CommunityResolver {
|
||||
if (homeCom.foreign) {
|
||||
throw new LogError('Error: Only the HomeCommunity could be modified!')
|
||||
}
|
||||
if (homeCom.gmsApiKey !== gmsApiKey || homeCom.location !== location) {
|
||||
if (
|
||||
homeCom.gmsApiKey !== gmsApiKey ||
|
||||
homeCom.location !== location ||
|
||||
homeCom.hieroTopicId !== hieroTopicId
|
||||
) {
|
||||
homeCom.gmsApiKey = gmsApiKey ?? null
|
||||
if (location) {
|
||||
homeCom.location = Location2Point(location)
|
||||
}
|
||||
homeCom.hieroTopicId = hieroTopicId ?? null
|
||||
await DbCommunity.save(homeCom)
|
||||
}
|
||||
return new Community(homeCom)
|
||||
|
||||
@ -423,13 +423,13 @@ describe('Contribution Links', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('returns an error if memo is longer than 255 characters', async () => {
|
||||
it('returns an error if memo is longer than 512 characters', async () => {
|
||||
jest.clearAllMocks()
|
||||
const { errors: errorObjects } = await mutate({
|
||||
mutation: createContributionLink,
|
||||
variables: {
|
||||
...variables,
|
||||
memo: '1234567890123456789212345678931234567894123456789512345678961234567897123456789812345678991234567890123456789012345678921234567893123456789412345678951234567896123456789712345678981234567899123456789012345678901234567892123456789312345678941234567895123456',
|
||||
memo: '123456789012345678921234567893123456789412345678951234567896123456789712345678981234567899123456789012345678901234567892123456789312345678941234567895123456789612345678971234567898123456789912345678901234567890123456789212345678931234567894123456789512345612345678901234567892123456789312345678941234567895123456789612345678971234567898123456789912345678901234567890123456789212345678931234567894123456789512345678961234567897123456789812345678991234567890123456789012345678921234567893123456789412345678951234567',
|
||||
},
|
||||
})
|
||||
expect(errorObjects).toMatchObject([
|
||||
@ -441,7 +441,7 @@ describe('Contribution Links', () => {
|
||||
{
|
||||
property: 'memo',
|
||||
constraints: {
|
||||
maxLength: 'memo must be shorter than or equal to 255 characters',
|
||||
maxLength: 'memo must be shorter than or equal to 512 characters',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@ -229,14 +229,14 @@ describe('ContributionResolver', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('throws error when memo length greater than 255 chars', async () => {
|
||||
it('throws error when memo length greater than 512 chars', async () => {
|
||||
jest.clearAllMocks()
|
||||
const date = new Date()
|
||||
const { errors: errorObjects } = await mutate({
|
||||
mutation: createContribution,
|
||||
variables: {
|
||||
amount: 100.0,
|
||||
memo: 'Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test',
|
||||
memo: 'Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test',
|
||||
contributionDate: date.toString(),
|
||||
},
|
||||
})
|
||||
@ -249,7 +249,7 @@ describe('ContributionResolver', () => {
|
||||
{
|
||||
property: 'memo',
|
||||
constraints: {
|
||||
maxLength: 'memo must be shorter than or equal to 255 characters',
|
||||
maxLength: 'memo must be shorter than or equal to 512 characters',
|
||||
},
|
||||
},
|
||||
],
|
||||
@ -398,7 +398,7 @@ describe('ContributionResolver', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('Memo length greater than 255 chars', () => {
|
||||
describe('Memo length greater than 512 chars', () => {
|
||||
it('throws error', async () => {
|
||||
jest.clearAllMocks()
|
||||
const date = new Date()
|
||||
@ -407,7 +407,7 @@ describe('ContributionResolver', () => {
|
||||
variables: {
|
||||
contributionId: pendingContribution.data.createContribution.id,
|
||||
amount: 100.0,
|
||||
memo: 'Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test',
|
||||
memo: 'Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test',
|
||||
contributionDate: date.toString(),
|
||||
},
|
||||
})
|
||||
@ -420,7 +420,7 @@ describe('ContributionResolver', () => {
|
||||
{
|
||||
property: 'memo',
|
||||
constraints: {
|
||||
maxLength: 'memo must be shorter than or equal to 255 characters',
|
||||
maxLength: 'memo must be shorter than or equal to 512 characters',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@ -187,7 +187,7 @@ describe('TransactionLinkResolver', () => {
|
||||
variables: {
|
||||
identifier: 'peter@lustig.de',
|
||||
amount: 100,
|
||||
memo: 'test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test t',
|
||||
memo: 'test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test',
|
||||
},
|
||||
})
|
||||
expect(errorObjects).toMatchObject([
|
||||
@ -199,7 +199,7 @@ describe('TransactionLinkResolver', () => {
|
||||
{
|
||||
property: 'memo',
|
||||
constraints: {
|
||||
maxLength: 'memo must be shorter than or equal to 255 characters',
|
||||
maxLength: 'memo must be shorter than or equal to 512 characters',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@ -269,7 +269,7 @@ describe('send coins', () => {
|
||||
recipientCommunityIdentifier: homeCom.communityUuid,
|
||||
recipientIdentifier: 'peter@lustig.de',
|
||||
amount: 100,
|
||||
memo: 'test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test t',
|
||||
memo: 'test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test',
|
||||
},
|
||||
})
|
||||
expect(errorObjects).toMatchObject([
|
||||
@ -281,7 +281,7 @@ describe('send coins', () => {
|
||||
{
|
||||
property: 'memo',
|
||||
constraints: {
|
||||
maxLength: 'memo must be shorter than or equal to 255 characters',
|
||||
maxLength: 'memo must be shorter than or equal to 512 characters',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@ -8,7 +8,7 @@ export const FULL_CREATION_AVAILABLE = [
|
||||
]
|
||||
export const CONTRIBUTIONLINK_NAME_MAX_CHARS = 100
|
||||
export const CONTRIBUTIONLINK_NAME_MIN_CHARS = 5
|
||||
export const MEMO_MAX_CHARS = 255
|
||||
export const MEMO_MAX_CHARS = 512
|
||||
export const MEMO_MIN_CHARS = 5
|
||||
export const DEFAULT_PAGINATION_PAGE_SIZE = 25
|
||||
export const FRONTEND_CONTRIBUTIONS_ITEM_ANCHOR_PREFIX = 'contributionListItem-'
|
||||
|
||||
@ -92,7 +92,7 @@ export const GMS_ACTIVE = Joi.boolean()
|
||||
.required()
|
||||
|
||||
export const GDT_ACTIVE = Joi.boolean()
|
||||
.description('Flag to indicate if the GMS (Geographic Member Search) service is used.')
|
||||
.description('Flag to indicate if the GDT (Gradido Transform) service is used.')
|
||||
.default(false)
|
||||
.required()
|
||||
|
||||
|
||||
@ -56,27 +56,32 @@ ENV PATH="/root/.bun/bin:${PATH}"
|
||||
FROM bun-base as installer
|
||||
|
||||
COPY --chown=app:app . .
|
||||
RUN bun install --filter database --production --no-cache --frozen-lockfile
|
||||
|
||||
##################################################################################
|
||||
# Build Shared ###################################################################
|
||||
##################################################################################
|
||||
FROM installer as build-shared
|
||||
|
||||
RUN bun install --filter shared --no-cache --frozen-lockfile \
|
||||
&& cd shared && yarn typecheck && yarn build
|
||||
|
||||
##################################################################################
|
||||
# Build ##########################################################################
|
||||
##################################################################################
|
||||
FROM installer as build
|
||||
|
||||
RUN bun install --no-cache --frozen-lockfile \
|
||||
&& cd shared && yarn build \
|
||||
&& cd ../database && yarn build && yarn typecheck
|
||||
RUN bun install --filter database --production --no-cache --frozen-lockfile
|
||||
|
||||
##################################################################################
|
||||
# PRODUCTION IMAGE ###############################################################
|
||||
##################################################################################
|
||||
FROM base as production
|
||||
|
||||
COPY --chown=app:app --from=installer ${DOCKER_WORKDIR}/src ./src
|
||||
COPY --chown=app:app --from=installer ${DOCKER_WORKDIR}/migration ./migration
|
||||
COPY --chown=app:app --from=installer ${DOCKER_WORKDIR}/node_modules ./node_modules
|
||||
COPY --chown=app:app --from=installer ${DOCKER_WORKDIR}/package.json ./package.json
|
||||
COPY --chown=app:app --from=installer ${DOCKER_WORKDIR}/tsconfig.json ./tsconfig.json
|
||||
COPY --chown=app:app --from=build-shared ${DOCKER_WORKDIR}/shared/build ./shared/build
|
||||
COPY --chown=app:app --from=build-shared ${DOCKER_WORKDIR}/shared/package.json ./shared/package.json
|
||||
COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/database ./database
|
||||
COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/node_modules ./node_modules
|
||||
COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/package.json ./package.json
|
||||
|
||||
##################################################################################
|
||||
# TEST UP ########################################################################
|
||||
@ -84,7 +89,7 @@ COPY --chown=app:app --from=installer ${DOCKER_WORKDIR}/tsconfig.json ./tsconfig
|
||||
FROM production as up
|
||||
|
||||
# Run command
|
||||
CMD /bin/sh -c "yarn up"
|
||||
CMD /bin/sh -c "cd database && yarn up"
|
||||
|
||||
##################################################################################
|
||||
# TEST RESET #####################################################################
|
||||
@ -92,7 +97,7 @@ CMD /bin/sh -c "yarn up"
|
||||
FROM production as reset
|
||||
|
||||
# Run command
|
||||
CMD /bin/sh -c "yarn reset"
|
||||
CMD /bin/sh -c "cd database && yarn reset"
|
||||
|
||||
##################################################################################
|
||||
# TEST DOWN ######################################################################
|
||||
@ -100,4 +105,4 @@ CMD /bin/sh -c "yarn reset"
|
||||
FROM production as down
|
||||
|
||||
# Run command
|
||||
CMD /bin/sh -c "yarn down"
|
||||
CMD /bin/sh -c "cd database && yarn down"
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
/* MIGRATION TO ADD hiero topic id IN COMMUNITY TABLE
|
||||
*
|
||||
* This migration adds fields for the hiero topic id in the community.table
|
||||
*/
|
||||
|
||||
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn(
|
||||
'ALTER TABLE `communities` ADD COLUMN `hiero_topic_id` varchar(512) DEFAULT NULL AFTER `location`;',
|
||||
)
|
||||
}
|
||||
|
||||
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn('ALTER TABLE `communities` DROP COLUMN `hiero_topic_id`;')
|
||||
}
|
||||
20
database/migration/migrations/0093-increase_memo_to_512.ts
Normal file
20
database/migration/migrations/0093-increase_memo_to_512.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/* MIGRATION TO INCREASE memo TO 512 in all tables which have a memo field
|
||||
*
|
||||
* This migration increases the memo field in all tables which have a memo field to 512
|
||||
*/
|
||||
|
||||
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn('ALTER TABLE `contributions` MODIFY COLUMN `memo` varchar(512) NOT NULL;')
|
||||
await queryFn('ALTER TABLE `contribution_links` MODIFY COLUMN `memo` varchar(512) NOT NULL;')
|
||||
await queryFn('ALTER TABLE `pending_transactions` MODIFY COLUMN `memo` varchar(512) NOT NULL;')
|
||||
await queryFn('ALTER TABLE `transactions` MODIFY COLUMN `memo` varchar(512) NOT NULL;')
|
||||
await queryFn('ALTER TABLE `transaction_links` MODIFY COLUMN `memo` varchar(512) NOT NULL;')
|
||||
}
|
||||
|
||||
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn('ALTER TABLE `contributions` MODIFY COLUMN `memo` varchar(255) NOT NULL;')
|
||||
await queryFn('ALTER TABLE `contribution_links` MODIFY COLUMN `memo` varchar(255) NOT NULL;')
|
||||
await queryFn('ALTER TABLE `pending_transactions` MODIFY COLUMN `memo` varchar(255) NOT NULL;')
|
||||
await queryFn('ALTER TABLE `transactions` MODIFY COLUMN `memo` varchar(255) NOT NULL;')
|
||||
await queryFn('ALTER TABLE `transaction_links` MODIFY COLUMN `memo` varchar(255) NOT NULL;')
|
||||
}
|
||||
@ -73,6 +73,9 @@ export class Community extends BaseEntity {
|
||||
})
|
||||
location: Geometry | null
|
||||
|
||||
@Column({ name: 'hiero_topic_id', type: 'varchar', length: 255, nullable: true })
|
||||
hieroTopicId: string | null
|
||||
|
||||
@CreateDateColumn({
|
||||
name: 'created_at',
|
||||
type: 'datetime',
|
||||
|
||||
@ -39,7 +39,7 @@ export class Contribution extends BaseEntity {
|
||||
@Column({ type: 'datetime', nullable: false, name: 'contribution_date' })
|
||||
contributionDate: Date
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
@Column({ type: 'varchar', length: 512, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
memo: string
|
||||
|
||||
@Column({
|
||||
|
||||
@ -10,7 +10,7 @@ export class ContributionLink extends BaseEntity {
|
||||
@Column({ type: 'varchar', length: 100, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
name: string
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
@Column({ type: 'varchar', length: 512, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
memo: string
|
||||
|
||||
@Column({ name: 'valid_from', type: 'datetime', nullable: false })
|
||||
|
||||
@ -71,7 +71,7 @@ export class PendingTransaction extends BaseEntity {
|
||||
})
|
||||
decayStart: Date | null
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
@Column({ type: 'varchar', length: 512, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
memo: string
|
||||
|
||||
@Column({ name: 'creation_date', type: 'datetime', precision: 3, nullable: true, default: null })
|
||||
|
||||
@ -70,7 +70,7 @@ export class Transaction extends BaseEntity {
|
||||
})
|
||||
decayStart: Date | null
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
@Column({ type: 'varchar', length: 512, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
memo: string
|
||||
|
||||
@Column({ name: 'creation_date', type: 'datetime', precision: 3, nullable: true, default: null })
|
||||
|
||||
@ -29,7 +29,7 @@ export class TransactionLink extends BaseEntity {
|
||||
})
|
||||
holdAvailableAmount: Decimal
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
@Column({ type: 'varchar', length: 512, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
memo: string
|
||||
|
||||
@Column({ type: 'varchar', length: 24, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
|
||||
@ -49,15 +49,16 @@ export const findUserByIdentifier = async (
|
||||
const user = userContact.user
|
||||
user.emailContact = userContact
|
||||
return user
|
||||
}
|
||||
}
|
||||
} else if (aliasSchema.safeParse(identifier).success) {
|
||||
return await DbUser.findOne({
|
||||
where: { alias: identifier, community: communityWhere },
|
||||
relations: ['emailContact', 'community'],
|
||||
})
|
||||
} else {
|
||||
// should don't happen often, so we create only in the rare case a logger for it
|
||||
getLogger(`${LOG4JS_QUERIES_CATEGORY_NAME}.user.findUserByIdentifier`).warn('Unknown identifier type', identifier)
|
||||
}
|
||||
// should don't happen often, so we create only in the rare case a logger for it
|
||||
getLogger(`${LOG4JS_QUERIES_CATEGORY_NAME}.user.findUserByIdentifier`).warn('Unknown identifier type', identifier)
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
1907
e2e-tests/bun.lock
Normal file
1907
e2e-tests/bun.lock
Normal file
File diff suppressed because it is too large
Load Diff
25
e2e-tests/playwright/typescript/bun.lock
Normal file
25
e2e-tests/playwright/typescript/bun.lock
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "typescript",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.53.1",
|
||||
"@types/node": "^24.0.7",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@playwright/test": ["@playwright/test@1.54.2", "", { "dependencies": { "playwright": "1.54.2" }, "bin": { "playwright": "cli.js" } }, "sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA=="],
|
||||
|
||||
"@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
||||
|
||||
"playwright": ["playwright@1.54.2", "", { "dependencies": { "playwright-core": "1.54.2" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw=="],
|
||||
|
||||
"playwright-core": ["playwright-core@1.54.2", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA=="],
|
||||
|
||||
"undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="],
|
||||
}
|
||||
}
|
||||
@ -161,7 +161,7 @@ const validationSchema = computed(() => {
|
||||
})), // date cannot be in the future
|
||||
memo: string()
|
||||
.min(5, ({ min }) => ({ key: 'form.validation.contributionMemo.min', values: { min } }))
|
||||
.max(255, ({ max }) => ({ key: 'form.validation.contributionMemo.max', values: { max } }))
|
||||
.max(512, ({ max }) => ({ key: 'form.validation.contributionMemo.max', values: { max } }))
|
||||
.required('form.validation.contributionMemo.required'),
|
||||
hours: number()
|
||||
.typeError({ key: 'form.validation.hours.typeError', values: { min: 0.01, max: maxHours } })
|
||||
|
||||
@ -40,11 +40,13 @@
|
||||
<BRow>
|
||||
<BCol cols="12" lg="5">
|
||||
<div>
|
||||
<gdd-amount
|
||||
:balance="balance"
|
||||
:show-status="false"
|
||||
:badge-show="false"
|
||||
/>
|
||||
<router-link to="transactions">
|
||||
<gdd-amount
|
||||
:balance="balance"
|
||||
:show-status="false"
|
||||
:badge-show="false"
|
||||
/>
|
||||
</router-link>
|
||||
</div>
|
||||
</BCol>
|
||||
<BCol cols="12" lg="7">
|
||||
@ -79,9 +81,7 @@
|
||||
<BRow>
|
||||
<BCol cols="12" lg="6">
|
||||
<div>
|
||||
<router-link to="transactions">
|
||||
<gdd-amount :balance="balance" :show-status="true" />
|
||||
</router-link>
|
||||
<gdd-amount :balance="balance" :show-status="true" />
|
||||
</div>
|
||||
</BCol>
|
||||
<BCol cols="12" lg="6">
|
||||
@ -104,13 +104,11 @@
|
||||
</BCol>
|
||||
<BCol cols="12" lg="6">
|
||||
<div>
|
||||
<router-link to="gdt">
|
||||
<gdt-amount
|
||||
:badge="true"
|
||||
:show-status="true"
|
||||
:gdt-balance="GdtBalance"
|
||||
/>
|
||||
</router-link>
|
||||
<gdt-amount
|
||||
:badge="true"
|
||||
:show-status="true"
|
||||
:gdt-balance="GdtBalance"
|
||||
/>
|
||||
</div>
|
||||
</BCol>
|
||||
</BRow>
|
||||
|
||||
@ -24,7 +24,7 @@ export const translateYupErrorString = (error, t) => {
|
||||
export const memo = string()
|
||||
.required('form.validation.memo.required')
|
||||
.min(5, ({ min }) => ({ key: 'form.validation.memo.min', values: { min } }))
|
||||
.max(255, ({ max }) => ({ key: 'form.validation.memo.max', values: { max } }))
|
||||
.max(512, ({ max }) => ({ key: 'form.validation.memo.max', values: { max } }))
|
||||
|
||||
export const identifier = string()
|
||||
.required('form.validation.identifier.required')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user