8000 feat: dynamic required fields for listings by bpsushi · Pull Request #4942 · bloom-housing/bloom · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: dynamic required fields for listings #4942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

bpsushi
Copy link
Collaborator
@bpsushi bpsushi commented Jun 4, 2025

This PR addresses #4630

  • Addresses the issue in full
  • Addresses only certain aspects of the issue

Description

This PR implements dynamic required listing fields functionality that allows jurisdictions to configure their own set of required fields for listing publication, addressing the need for different validation requirements across jurisdictions.

Key changes:

  • Added requiredFields column to jurisdictions table via migration
  • Updated Prisma schema to support JSON array of required field names
  • New validation pipeListingCreateUpdateValidationPipe that dynamically fetches jurisdiction-specific required fields
  • Updated DTOs -Added requiredFields property to listing DTOs with proper validation decorators
  • Modified listing service to strip requiredFields metadata before database persistence
  • Updated listing controller to use the new validation pipe
  • Enhanced @ValidateListingPublish decorator to handle dynamic field requirements
  • Added unit tests for the validation pipe
  • Updated existing tests to work with new validation architecture

How Can This Be Tested/Reviewed?

Local Testing:

  1. In API dir run yarn generate:client and apply migrations
  2. In API dir run yarn test
  3. In API dir run yarn test:e2e ./listing.e2e-spec.ts to test full validation flows

Author Checklist:

  • Added QA notes to the issue with applicable URLs
  • Reviewed in a desktop view
  • Reviewed in a mobile view
  • Reviewed considering accessibility
  • Added tests covering the changes
  • Made corresponding changes to the documentation
  • Ran yarn generate:client and/or created a migration when required

Review Process:

  • Read and understand the issue
  • Ensure the author has added QA notes
  • Review the code itself from a style point of view
  • Pull the changes down locally and test that the acceptance criteria is met
  • Either (1) explicitly ask a clarifying question, (2) request changes, or (3) approve the PR, even if there are very small remaining changes, if you don't need to re-review after the updates

@bpsushi bpsushi requested a review from ludtkemorgan June 4, 2025 10:37
@bpsushi bpsushi self-assigned this Jun 4, 2025
@bpsushi bpsushi added the 1 review needed Requires 1 more review before ready to merge label Jun 4, 2025
Copy link
netlify bot commented Jun 4, 2025

Deploy Preview for bloom-public-seeds ready!

Name Link
🔨 Latest commit 7ac0d2d
🔍 Latest deploy log https://app.netlify.com/projects/bloom-public-seeds/deploys/684021dc5c01e0000830350d
😎 Deploy Preview https://deploy-preview-4942--bloom-public-seeds.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
netlify bot commented Jun 4, 2025

Deploy Preview for partners-bloom-dev ready!

Name Link
🔨 Latest commit 7ac0d2d
🔍 Latest deploy log https://app.netlify.com/projects/partners-bloom-dev/deploys/684021dcbcc48300080996e4
😎 Deploy Preview https://deploy-preview-4942--partners-bloom-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
netlify bot commented Jun 4, 2025

Deploy Preview for bloom-exygy-dev ready!

Name Link
🔨 Latest commit 7ac0d2d
🔍 Latest deploy log https://app.netlify.com/projects/bloom-exygy-dev/deploys/684021dc06ea740008953c58
😎 Deploy Preview https://deploy-preview-4942--bloom-exygy-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
netlify bot commented Jun 4, 2025

Deploy Preview for partners-bloom-dev ready!

Name Link
🔨 Latest commit 6ad3095
🔍 Latest deploy log https://app.netlify.com/projects/partners-bloom-dev/deploys/6849e341cbea200008841eca
😎 Deploy Preview https://deploy-preview-4942--partners-bloom-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Collaborator
@ludtkemorgan ludtkemorgan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial testing looks great. Found a couple of minor things and will continue to test. I'll compile the list of default required fields

[ListingsStatusEnum.changesRequested]: ListingCreate,
};
// Default required fields if jurisdiction doesn't specify any
private defaultRequiredFields = [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: these aren't the default fields we would want. I can compile the list that we should have and report back

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ludtkemorgan of course - if you can provide valid list i will replace it

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the list that I'd recommend for the default:

    'listingsBuildingAddress',
    'name',
    'developer',
    'listingImages',
    'leasingAgentEmail',
    'leasingAgentName',
    'leasingAgentPhone',
    'jurisdictions',
    'units',
    'unitGroups',

One call out is that units and unitGroups are required because otherwise the ValidateUnitsRequired is not done. So a user would have to pass in an empty array to the field that they don't want as only 1 can be used on a jurisdiction

let jurisdictionA: IdDTO = { id: '' };

if (jurisdictionId) {
jurisdictionA.id = jurisdictionId;
} else {
jurisdictionA = await prisma.jurisdictions.create({
data: jurisdictionFactory(),
data: jurisdictionFactory(randomName()),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Are these randomName necessary? The jurisdictionFactory does the same function if nothing is passed in.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ludtkemorgan you are right it should not be necessary but for some reason without passing it explicitly generated names was often not unique and i had lot of database unique constraints errors.

TBH im not sure why (maybe testing env evaluate default values differently?) but i also did nit dived into this problem too deeply since passing randomName() as a param looks like a working workaround.

The other option is to just use faker lib.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We run into this issue sometimes on the circle-ci and github actions runs of the tests. The problem is the randomName takes from a set list of options in word-generator.ts so duplicates will happen. One option is to add a prefix here to randomName. listing-${randomName()}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can also use a name here and just pass along a name that would be unique. We probably should do one of those options to help reduce flakiness in the suite

@YazeedLoonat YazeedLoonat self-requested a review June 4, 2025 15:51
@YazeedLoonat YazeedLoonat added 2 reviews needed Requires 2 more review before ready to merge needs changes The author must make changes and then re-request review before merging and removed 1 review needed Requires 1 more review before ready to merge labels Jun 4, 2025
@ColinBuyck ColinBuyck self-requested a review June 11, 2025 20:11
@bpsushi bpsushi requested a review from ludtkemorgan June 11, 2025 20:15
Copy link
Collaborator
@ludtkemorgan ludtkemorgan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making those changes. I have added the list of default values I'd like to see so assuming those are a updated I can approve this.

Still want @YazeedLoonat to take a review pass before it's ready to merge

[ListingsStatusEnum.changesRequested]: ListingCreate,
};
// Default required fields if jurisdiction doesn't specify any
private defaultRequiredFields = [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the list that I'd recommend for the default:

    'listingsBuildingAddress',
    'name',
    'developer',
    'listingImages',
    'leasingAgentEmail',
    'leasingAgentName',
    'leasingAgentPhone',
    'jurisdictions',
    'units',
    'unitGroups',

One call out is that units and unitGroups are required because otherwise the ValidateUnitsRequired is not done. So a user would have to pass in an empty array to the field that they don't want as only 1 can be used on a jurisdiction

let jurisdictionA: IdDTO = { id: '' };

if (jurisdictionId) {
jurisdictionA.id = jurisdictionId;
} else {
jurisdictionA = await prisma.jurisdictions.create({
data: jurisdictionFactory(),
data: jurisdictionFactory(randomName()),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We run into this issue sometimes on the circle-ci and github actions runs of the tests. The problem is the randomName takes from a set list of options in word-generator.ts so duplicates will happen. One option is to add a prefix here to randomName. listing-${randomName()}

@@ -93,6 +93,7 @@ export const stagingSeed = async (
FeatureFlagEnum.enableCompanyWebsite,
FeatureFlagEnum.disableCommonApplication,
],
requiredListingFields: ['name', 'description'],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "description" isn't a real field for listings, can you change it to "listingsBuildingAddress"

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump since it still should get addressed

@ludtkemorgan ludtkemorgan added 1 review needed Requires 1 more review before ready to merge and removed 2 reviews needed Requires 2 more review before ready to merge labels Jun 12, 2025
Copy link
Collaborator
@YazeedLoonat YazeedLoonat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a bug that is allowing a field that is required (name) but has no value to pass the check

to test this I did the following:
stand up api and partners -> go to the partner site -> Add Listing -> hit Publish
we do get an error but that error is happening from the service level and not getting stopped in the dto level for missing a name

Also with just a name we are still failing because a jurisdiction is missing which to me points to a need for us to require the jurisdiction as part of our minimum fields

-- CreateIndex

CREATE INDEX "applications_user_id_idx" ON "applications"("user_id");
-- CreateIndex (only if it doesn't exist)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: I don't think you need this file at all, can drop

@@ -93,6 +93,7 @@ export const stagingSeed = async (
FeatureFlagEnum.enableCompanyWebsite,
FeatureFlagEnum.disableCommonApplication,
],
requiredListingFields: ['name', 'description'],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump since it still should get addressed

}

static isPublishing(status?: ListingsStatusEnum | ''): boolean {
/*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: we use jsdoc comment notation usually on the API
you can peep the script-runner.service.ts to see examples

let jurisdictionA: IdDTO = { id: '' };

if (jurisdictionId) {
jurisdictionA.id = jurisdictionId;
} else {
jurisdictionA = await prisma.jurisdictions.create({
data: jurisdictionFactory(),
data: jurisdictionFactory(randomName()),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can also use a name here and just pass along a name that would be unique. We probably should do one of those options to help reduce flakiness in the suite

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1 review needed Requires 1 more review before ready to merge needs changes The author must make changes and then re-request review before merging
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0