From deca0d39aea75cae79f06237fbbc3683aea46c49 Mon Sep 17 00:00:00 2001 From: quantum-grit <91589884+quantum-grit@users.noreply.github.com> Date: Fri, 29 Sep 2023 10:54:50 +0300 Subject: [PATCH 1/4] beneficiery without mail (#555) * added: env variable for CAMPAIGN_ADMIN_MAIL in deployment config * added default build command for vscode * person email is now nullable * fixed compiler errors after person.email become nullable * formatting * make email optional for createPersonDto --- .vscode/tasks.json | 16 ++++++++++++++ apps/api/src/auth/auth.service.ts | 22 ++++++++++--------- .../generated/person/dto/create-person.dto.ts | 2 +- .../person/entities/person.entity.ts | 2 +- .../api/src/donations/donations.controller.ts | 16 ++------------ apps/api/src/donations/donations.service.ts | 6 ++--- .../notifications/notifications.service.ts | 4 ++-- apps/api/src/person/dto/create-person.dto.ts | 3 ++- apps/api/src/person/person.service.ts | 6 ++--- .../migration.sql | 2 ++ podkrepi.dbml | 2 +- schema.prisma | 2 +- 12 files changed, 46 insertions(+), 37 deletions(-) create mode 100644 .vscode/tasks.json create mode 100644 migrations/20230925152101_make_person_email_optional/migration.sql diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..e40aca163 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,16 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "build", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "label": "npm: build", + "detail": "yarn build" + } + ] +} diff --git a/apps/api/src/auth/auth.service.ts b/apps/api/src/auth/auth.service.ts index a2b7988c6..0035171d3 100644 --- a/apps/api/src/auth/auth.service.ts +++ b/apps/api/src/auth/auth.service.ts @@ -203,9 +203,9 @@ export class AuthService { await this.marketingNotificationsService.provider.addContactsToList({ contacts: [ { - email: person.email, - first_name: person?.firstName || '', - last_name: person?.lastName || '', + email: registerDto.email, + first_name: registerDto.firstName, + last_name: registerDto.lastName, }, ], list_ids: [mainList], @@ -327,13 +327,15 @@ export class AuthService { async sendMailForPasswordChange(forgotPasswordDto: ForgottenPasswordEmailDto) { const stage = this.config.get('APP_ENV') === 'development' ? 'APP_URL_LOCAL' : 'APP_URL' - const user = await this.prismaService.person.findFirst({ + const person = await this.prismaService.person.findFirst({ where: { email: forgotPasswordDto.email }, }) - if (!user) { + + if (!person || !person.email) { throw new NotFoundException('Invalid email') } - const payload = { username: user.email, sub: user.keycloakId } + + const payload = { username: person.email, sub: person.keycloakId } const jtwSecret = process.env.JWT_SECRET_KEY const access_token = this.jwtService.sign(payload, { secret: jtwSecret, @@ -342,12 +344,12 @@ export class AuthService { const appUrl = this.config.get(stage) const link = `${appUrl}/change-password?token=${access_token}` const profile = { - email: user.email, - firstName: user.firstName, - lastName: user.lastName, + email: person.email, + firstName: person.firstName, + lastName: person.lastName, link: link, } - const userEmail = { to: [user.email] } + const userEmail = { to: [person.email] } const mail = new ForgottenPasswordMailDto(profile) await this.sendEmail.sendFromTemplate(mail, userEmail, { //Allow users to receive the mail, regardles of unsubscribes diff --git a/apps/api/src/domain/generated/person/dto/create-person.dto.ts b/apps/api/src/domain/generated/person/dto/create-person.dto.ts index 12fd44d47..a00ddc345 100644 --- a/apps/api/src/domain/generated/person/dto/create-person.dto.ts +++ b/apps/api/src/domain/generated/person/dto/create-person.dto.ts @@ -1,7 +1,7 @@ export class CreatePersonDto { firstName: string lastName: string - email: string + email?: string phone?: string company?: string newsletter?: boolean diff --git a/apps/api/src/domain/generated/person/entities/person.entity.ts b/apps/api/src/domain/generated/person/entities/person.entity.ts index eb6493a36..70484e54e 100644 --- a/apps/api/src/domain/generated/person/entities/person.entity.ts +++ b/apps/api/src/domain/generated/person/entities/person.entity.ts @@ -23,7 +23,7 @@ export class Person { id: string firstName: string lastName: string - email: string + email: string | null phone: string | null company: string | null createdAt: Date diff --git a/apps/api/src/donations/donations.controller.ts b/apps/api/src/donations/donations.controller.ts index 1d153de38..d79272110 100644 --- a/apps/api/src/donations/donations.controller.ts +++ b/apps/api/src/donations/donations.controller.ts @@ -12,7 +12,6 @@ import { Res, Inject, forwardRef, - NotFoundException, } from '@nestjs/common' import { ApiQuery, ApiTags } from '@nestjs/swagger' import { DonationStatus } from '@prisma/client' @@ -108,9 +107,7 @@ export class DonationsController { @Get('user-donations') async userDonations(@AuthenticatedUser() user: KeycloakTokenParsed) { - const person = await this.personService.findOneByKeycloakId(user.sub) - if (!person) throw new NotFoundException('User was not found') - return await this.donationsService.getDonationsByUser(user.sub, person.email) + return await this.donationsService.getDonationsByUser(user.sub, user.email) } @Get('money') @@ -178,16 +175,7 @@ export class DonationsController { @Get('user/:id') async userDonationById(@Param('id') id: string, @AuthenticatedUser() user: KeycloakTokenParsed) { - const person = await this.personService.findOneByKeycloakId(user.sub) - if (!person) throw new NotFoundException('User was not found') - const donation = await this.donationsService.getUserDonationById(id, user.sub, person.email) - return { - ...donation, - person: { - firstName: person.firstName, - lastName: person.lastName, - }, - } + return await this.donationsService.getUserDonationById(id, user.sub, user.email) } @Post('payment-intent') diff --git a/apps/api/src/donations/donations.service.ts b/apps/api/src/donations/donations.service.ts index 33ac3c344..ed6eb1f0f 100644 --- a/apps/api/src/donations/donations.service.ts +++ b/apps/api/src/donations/donations.service.ts @@ -423,7 +423,7 @@ export class DonationsService { async getUserDonationById( id: string, keycloakId: string, - email: string, + email?: string, ): Promise<(Donation & { person: Person | null }) | null> { return await this.prisma.donation.findFirst({ where: { @@ -564,7 +564,7 @@ export class DonationsService { const status = updatePaymentDto.status || currentDonation.status let donorId = currentDonation.personId - let billingEmail = '' + let billingEmail: string | null = '' if ( (updatePaymentDto.targetPersonId && currentDonation.personId !== updatePaymentDto.targetPersonId) || @@ -636,7 +636,7 @@ export class DonationsService { } } - async getDonationsByUser(keycloakId: string, email: string) { + async getDonationsByUser(keycloakId: string, email?: string) { const donations = await this.prisma.donation.findMany({ where: { OR: [{ billingEmail: email }, { person: { keycloakId } }], diff --git a/apps/api/src/notifications/notifications.service.ts b/apps/api/src/notifications/notifications.service.ts index 45b3a5398..0c6ec988d 100644 --- a/apps/api/src/notifications/notifications.service.ts +++ b/apps/api/src/notifications/notifications.service.ts @@ -272,7 +272,7 @@ export class MarketingNotificationsService { return new BadRequestException('Failed to get user') } - if (!userInfo) return new BadRequestException('User not found') + if (!userInfo || !userInfo.email) return new BadRequestException('User not found') // Already unsubscribed if (!userInfo.newsletter) return { email: userInfo.email, subscribed: false } @@ -306,7 +306,7 @@ export class MarketingNotificationsService { return new BadRequestException('Failed to get user') } - if (!userInfo) return new BadRequestException('User not found') + if (!userInfo || !userInfo.email) return new BadRequestException('User not found') // Already subscribed if (userInfo.newsletter) return { email: userInfo.email, subscribed: true } diff --git a/apps/api/src/person/dto/create-person.dto.ts b/apps/api/src/person/dto/create-person.dto.ts index 322a592be..64b3b25ac 100644 --- a/apps/api/src/person/dto/create-person.dto.ts +++ b/apps/api/src/person/dto/create-person.dto.ts @@ -16,7 +16,8 @@ export class CreatePersonDto { @ApiProperty() @Expose() @IsEmail() - email: string + @IsOptional() + email?: string @ApiProperty() @Expose() diff --git a/apps/api/src/person/person.service.ts b/apps/api/src/person/person.service.ts index 3f8c553fa..a7d4ae702 100644 --- a/apps/api/src/person/person.service.ts +++ b/apps/api/src/person/person.service.ts @@ -1,6 +1,6 @@ import { Injectable, Logger } from '@nestjs/common' import { ConfigService } from '@nestjs/config' -import client from '@sendgrid/client' +import mailClient from '@sendgrid/client' import { Prisma } from '@prisma/client' import { PrismaService } from '../prisma/prisma.service' import { CreatePersonDto } from './dto/create-person.dto' @@ -16,7 +16,7 @@ export class PersonService { const apiKey = config.get('sendgrid.apiKey') if (apiKey && this.contactsUrl) { - client.setApiKey(apiKey) + mailClient.setApiKey(apiKey) } else { this.enabled = false Logger.warn('no apiKey or contactsUrl for sendgrid, will not add user to the contact list') @@ -138,7 +138,7 @@ export class PersonService { } try { - await client.request({ + await mailClient.request({ url: this.contactsUrl, method: 'PUT', body: data, diff --git a/migrations/20230925152101_make_person_email_optional/migration.sql b/migrations/20230925152101_make_person_email_optional/migration.sql new file mode 100644 index 000000000..ea2cfd418 --- /dev/null +++ b/migrations/20230925152101_make_person_email_optional/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "people" ALTER COLUMN "email" DROP NOT NULL; diff --git a/podkrepi.dbml b/podkrepi.dbml index f06bf0a63..89e170192 100644 --- a/podkrepi.dbml +++ b/podkrepi.dbml @@ -11,7 +11,7 @@ Table people { id String [pk] firstName String [not null] lastName String [not null] - email String [unique, not null] + email String [unique] phone String company String createdAt DateTime [default: `now()`, not null] diff --git a/schema.prisma b/schema.prisma index ac34c82cd..a2868c97e 100644 --- a/schema.prisma +++ b/schema.prisma @@ -34,7 +34,7 @@ model Person { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid firstName String @map("first_name") @db.VarChar(100) lastName String @map("last_name") @db.VarChar(100) - email String @unique @db.Citext + email String? @unique @db.Citext phone String? @db.VarChar(50) company String? @db.VarChar(50) createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) From afd94b68cc017bd67b0a9f5b34e693fb4e17897c Mon Sep 17 00:00:00 2001 From: quantum-grit <91589884+quantum-grit@users.noreply.github.com> Date: Fri, 29 Sep 2023 10:55:29 +0300 Subject: [PATCH 2/4] fix expense seeding (#554) * added: env variable for CAMPAIGN_ADMIN_MAIL in deployment config * ensure all campaigns have single vault and heavily-funded campaign has approved expenses * fixed: typescript errors in expense tests --- .../src/expenses/expenses.controller.spec.ts | 33 ++-- db/seed/campaign/seed.ts | 2 +- db/seed/donation/seed.ts | 19 ++- db/seed/expense/factory.ts | 4 +- db/seed/expense/seed.ts | 19 ++- db/seed/vault/seed.ts | 150 ++++-------------- 6 files changed, 88 insertions(+), 139 deletions(-) diff --git a/apps/api/src/expenses/expenses.controller.spec.ts b/apps/api/src/expenses/expenses.controller.spec.ts index 254c36ac9..4f8c5e6f9 100644 --- a/apps/api/src/expenses/expenses.controller.spec.ts +++ b/apps/api/src/expenses/expenses.controller.spec.ts @@ -2,11 +2,12 @@ import { Test, TestingModule } from '@nestjs/testing' import { ExpensesController } from './expenses.controller' import { ExpensesService } from './expenses.service' import { MockPrismaService, prismaMock } from '../prisma/prisma-client.mock' -import { ExpenseStatus, ExpenseType, Currency } from '@prisma/client' +import { ExpenseStatus, ExpenseType, Currency, Person, Campaign } from '@prisma/client' import { mockReset } from 'jest-mock-extended' import { CreateExpenseDto } from './dto/create-expense.dto' import { UpdateExpenseDto } from './dto/update-expense.dto' import { S3Service } from '../s3/s3.service' +import { KeycloakTokenParsed } from '../auth/keycloak' const mockData = [ { @@ -69,8 +70,8 @@ describe('ExpensesController', () => { const campaign = {} const user = { sub: '00000000-0000-0000-0000-000000000013' } - prismaMock.person.findFirst.mockResolvedValue(person) - prismaMock.campaign.findFirst.mockResolvedValue(campaign) + prismaMock.person.findFirst.mockResolvedValue(person as Person) + prismaMock.campaign.findFirst.mockResolvedValue(campaign as Campaign) prismaMock.expense.create.mockResolvedValue(expense) prismaMock.vault.update.mockResolvedValue(vault) prismaMock.vault.findFirst.mockResolvedValue(vault) @@ -78,7 +79,7 @@ describe('ExpensesController', () => { const createDto: CreateExpenseDto = { ...expense } - const result = await controller.create(user, createDto, []) + const result = await controller.create(user as KeycloakTokenParsed, createDto) expect(result).toEqual(expense) expect(prismaMock.expense.create).toHaveBeenCalledWith({ data: createDto }) @@ -132,8 +133,8 @@ describe('ExpensesController', () => { const campaign = {} - prismaMock.person.findFirst.mockResolvedValue(person) - prismaMock.campaign.findFirst.mockResolvedValue(campaign) + prismaMock.person.findFirst.mockResolvedValue(person as Person) + prismaMock.campaign.findFirst.mockResolvedValue(campaign as Campaign) prismaMock.vault.findFirstOrThrow.mockResolvedValue(vault) prismaMock.expense.findFirstOrThrow.mockResolvedValue(expense) prismaMock.vault.update.mockResolvedValue(vault) @@ -147,7 +148,7 @@ describe('ExpensesController', () => { } // act - const result = await controller.update(user, expense.id, updateDto) + const result = await controller.update(user as KeycloakTokenParsed, expense.id, updateDto) // assert expect(result).toEqual(expense) @@ -193,7 +194,9 @@ describe('ExpensesController', () => { vaultId: vault.id, } - await expect(controller.update(user, expense.id, updateDto)).rejects.toThrow() + await expect( + controller.update(user as KeycloakTokenParsed, expense.id, updateDto), + ).rejects.toThrow() //expect an exception expect(prismaMock.expense.update).not.toHaveBeenCalled() }) @@ -233,8 +236,12 @@ describe('ExpensesController', () => { } // assert - await expect(controller.update(user, approvedExpense.id, updateDto)).rejects.toThrow() - await expect(controller.update(user, cancelledExpense.id, updateDto)).rejects.toThrow() + await expect( + controller.update(user as KeycloakTokenParsed, approvedExpense.id, updateDto), + ).rejects.toThrow() + await expect( + controller.update(user as KeycloakTokenParsed, cancelledExpense.id, updateDto), + ).rejects.toThrow() expect(prismaMock.expense.update).not.toHaveBeenCalled() expect(prismaMock.vault.update).not.toHaveBeenCalled() }) @@ -242,6 +249,10 @@ describe('ExpensesController', () => { it('should not update an expense, when its vault is being changed', async () => { const expense = mockData[0] + const user: KeycloakTokenParsed = { + sub: '00000000-0000-0000-0000-000000000012', + } as KeycloakTokenParsed + const vault = { id: '00000000-0000-0000-0000-000000000016', name: 'vault1', @@ -262,7 +273,7 @@ describe('ExpensesController', () => { } // assert - await expect(controller.update(expense.id, updateDto)).rejects.toThrow() + await expect(controller.update(user, expense.id, updateDto)).rejects.toThrow() expect(prismaMock.expense.update).not.toHaveBeenCalled() expect(prismaMock.vault.update).not.toHaveBeenCalled() }) diff --git a/db/seed/campaign/seed.ts b/db/seed/campaign/seed.ts index 6c0ca77f0..9c4204366 100644 --- a/db/seed/campaign/seed.ts +++ b/db/seed/campaign/seed.ts @@ -15,7 +15,7 @@ const prisma = new PrismaClient() const SEED_ACTIVE_CAMPAIGNS = 5 const SEED_RANDOM_CAMPAIGNS = 5 const SEED_COMPLETED_CAMPAIGNS = 3 -const SEED_HEAVILY_FUNDED_CAMPAIGNS = 3 +const SEED_HEAVILY_FUNDED_CAMPAIGNS = 1 export async function campaignSeed() { console.log('Campaigns seed') diff --git a/db/seed/donation/seed.ts b/db/seed/donation/seed.ts index e1870d16b..6c0736984 100644 --- a/db/seed/donation/seed.ts +++ b/db/seed/donation/seed.ts @@ -1,4 +1,11 @@ -import { PrismaClient, PaymentProvider, DonationStatus, DonationType, Person } from '@prisma/client' +import { + PrismaClient, + PaymentProvider, + DonationStatus, + DonationType, + Person, + CampaignState, +} from '@prisma/client' import { donationFactory } from './factory' @@ -78,8 +85,8 @@ async function seedRandomDonations({ person }: SeedData) { async function seedDonationsForCompletedCampaign({ person }: SeedData) { const completedCampaignVault = await prisma.vault.findFirst({ where: { - name: { - contains: 'completed', + campaign: { + state: CampaignState.complete, }, }, }) @@ -119,8 +126,10 @@ async function seedDonationsForCompletedCampaign({ person }: SeedData) { async function seedDonationsForHeavilyFundedCampaign({ person }: SeedData) { const heavilyFundedCampaignVault = await prisma.vault.findFirst({ where: { - name: { - contains: 'heavily-funded', + campaign: { + title: { + contains: 'heavily-funded', + }, }, }, }) diff --git a/db/seed/expense/factory.ts b/db/seed/expense/factory.ts index 07b47c9b9..82a74310a 100644 --- a/db/seed/expense/factory.ts +++ b/db/seed/expense/factory.ts @@ -11,9 +11,9 @@ export const expenseFactory = Factory.define(({ associations }) => ({ vaultId: associations.vaultId || faker.datatype.uuid(), documentId: associations.documentId || null, approvedById: associations.approvedById || null, - amount: faker.datatype.number(), + amount: faker.datatype.number({ min: 1, max: 20000 }), currency: faker.helpers.arrayElement(Object.values(Currency)), - status: faker.helpers.arrayElement(Object.values(ExpenseStatus)), + status: ExpenseStatus.pending, deleted: faker.datatype.boolean(), spentAt: faker.date.past(), })) diff --git a/db/seed/expense/seed.ts b/db/seed/expense/seed.ts index f0ed692d4..cb164999f 100644 --- a/db/seed/expense/seed.ts +++ b/db/seed/expense/seed.ts @@ -6,18 +6,33 @@ const prisma = new PrismaClient() export async function expenseSeed() { console.log('Expense seed') - const vault = await prisma.vault.findFirst() + const vault = await prisma.vault.findFirst({ + where: { + campaign: { + title: { + contains: 'heavily-funded', + }, + }, + }, + }) if (!vault) { throw new Error('There are no vaults created yet!') } + const coordinator = await prisma.coordinator.findFirst() + + if (!coordinator) { + throw new Error('There are no coordinators created yet!') + } + const expensesData: Expense[] = expenseFactory.buildList( - 20, + 11, {}, { associations: { vaultId: vault.id, + approvedById: coordinator.personId, }, }, ) diff --git a/db/seed/vault/seed.ts b/db/seed/vault/seed.ts index 0baadf38b..6cfd2dfe9 100644 --- a/db/seed/vault/seed.ts +++ b/db/seed/vault/seed.ts @@ -7,123 +7,37 @@ const prisma = new PrismaClient() export async function vaultSeed() { console.log('Vault seed') - await seedVaultsForRandomCampaign() - await seedVaultForCompletedCampaign() - await seedVaultForHeavilyFundedCampaign() -} - -async function seedVaultsForRandomCampaign() { - const campaign = await prisma.campaign - .findMany() - .then((campaigns) => faker.helpers.arrayElement(campaigns)) - - if (!campaign) { - throw new Error('There are no campaigns created yet!') - } - - const randomCampaignVaultsData: Vault[] = vaultFactory.buildList( - 20, - { - currency: Currency.BGN, - amount: 0, // Initializing with 0 and fill the correct amount after donations have been seeded - }, - { - associations: { - campaignId: campaign.id, - }, - }, - ) - - const insertRandomCampaignVaults = await prisma.vault.createMany({ - data: randomCampaignVaultsData, - skipDuplicates: true, - }) - - console.log({ insertRandomCampaignVaults }) -} - -async function seedVaultForCompletedCampaign() { - const completedCampaign = await prisma.campaign.findFirst({ - where: { - state: CampaignState.complete, - }, - }) - - if (!completedCampaign) { - throw new Error('There is no completed campaign created') - } - - const completedCampaignVault = await prisma.vault.findFirst({ - where: { - campaignId: completedCampaign.id, - }, - }) - - if (completedCampaignVault) { - console.log('{ Completed campaign vault already exists }') - return + await seedVaultsForCampaigns() + + async function seedVaultsForCampaigns() { + const campaigns = await prisma.campaign.findMany() + + if (!campaigns) { + throw new Error('There are no campaigns created yet!') + } + + let vaults: Vault[] = [] + campaigns.map(async (campaign) => { + vaults.push( + vaultFactory.build( + { + currency: Currency.BGN, + amount: 0, // Initializing with 0 and fill the correct amount after donations have been seeded + }, + { + associations: { + campaignId: campaign.id, + }, + }, + ), + ) + }) + + const insertRandomCampaignVaults = await prisma.vault.createMany({ + data: vaults, + skipDuplicates: true, + }) + + console.log({ insertRandomCampaignVaults }) } - - const completedCampaignVaultData: Vault = vaultFactory.build( - { - name: faker.finance.accountName() + ' completed', - currency: Currency.BGN, - amount: 0, // Initializing with 0 and fill the correct amount after donations have been seeded - }, - { - associations: { - campaignId: completedCampaign.id, - }, - }, - ) - - const insertCompletedCampaignVault = await prisma.vault.create({ - data: completedCampaignVaultData, - }) - - console.log(`{ insertCompletedCampaignVault: ${!!insertCompletedCampaignVault} }`) -} - -async function seedVaultForHeavilyFundedCampaign() { - const heavilyFundedCampaign = await prisma.campaign.findFirst({ - where: { - title: { - contains: 'heavily-funded', - }, - }, - }) - - if (!heavilyFundedCampaign) { - throw new Error('There is no heavily funded campaign created') - } - - const heavilyFundedCampaignVault = await prisma.vault.findFirst({ - where: { - campaignId: heavilyFundedCampaign.id, - }, - }) - - if (heavilyFundedCampaignVault) { - console.log('{ Heavily-funded campaign vault already exists }') - return - } - - const heavilyFundedCampaignVaultData: Vault = vaultFactory.build( - { - name: faker.finance.accountName() + ' heavily-funded', - currency: Currency.BGN, - amount: 0, // Initializing with 0 and fill the correct amount after donations have been seeded - }, - { - associations: { - campaignId: heavilyFundedCampaign.id, - }, - }, - ) - - const insertHeavilyFundedCampaignVault = await prisma.vault.create({ - data: heavilyFundedCampaignVaultData, - }) - - console.log(`{ insertHeavilyFundedCampaignVault: ${!!insertHeavilyFundedCampaignVault} }`) } From 87599aba12971924a3c87e29ffb2363588836bf3 Mon Sep 17 00:00:00 2001 From: igoychev Date: Fri, 29 Sep 2023 12:03:11 +0300 Subject: [PATCH 3/4] Update README.md visual changes --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 363aedcc5..7aa9eceea 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,9 @@ This will start the following services in your local docker: - Local Postgres DB on default port 5432 for your personal development - Local Keycloak Identity server Admin UI on with config coming from `./manifests/keycloak/config`: - Keycloak Admin User: `admin` with pass: `admin` - - Podkrepi realm users: coordinator@podkrepi.bg, reviewer@podkrepi.bg, admin@podkrepi.bg, all with pass: `$ecurePa33` + - Podkrepi Admin users: + - coordinator@podkrepi.bg, reviewer@podkrepi.bg, admin@podkrepi.bg, + - all with pass: `$ecurePa33` ## Initialize the Database with Prisma Migration scripts From 15467e495ae1bedb887fa19fed71ecf5d582c34b Mon Sep 17 00:00:00 2001 From: igoychev Date: Fri, 29 Sep 2023 13:03:09 +0300 Subject: [PATCH 4/4] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7aa9eceea..53f38eabc 100644 --- a/README.md +++ b/README.md @@ -84,8 +84,8 @@ This will start the following services in your local docker: - Local Postgres DB on default port 5432 for your personal development - Local Keycloak Identity server Admin UI on with config coming from `./manifests/keycloak/config`: - - Keycloak Admin User: `admin` with pass: `admin` - - Podkrepi Admin users: + - Keycloak Local Admin User: `admin` with pass: `admin` + - Podkrepi Local Admin users: - coordinator@podkrepi.bg, reviewer@podkrepi.bg, admin@podkrepi.bg, - all with pass: `$ecurePa33`