Skip to content

Commit

Permalink
Release: 2023-09-05 (#643)
Browse files Browse the repository at this point in the history
* chore(deps): bump http-cache-semantics from 4.1.0 to 4.1.1 (bloom-housing#3522)

* chore(deps): bump fast-xml-parser from 4.1.3 to 4.2.4 (bloom-housing#3500)

* chore(deps): bump @sideway/formula from 3.0.0 to 3.0.1 (bloom-housing#3354)

* fix: remove updated_at field from listing details page (bloom-housing#3527)

* feat: uptake field value v2 (bloom-housing#3509)

* fix: partners listings table sort by status (bloom-housing#3576)

* fix: add sorting by status

* fix: change default sort to status

* fix: default sorting by status

* fix: sort by application when the same status

* fix: orderBy test using default value

* fix: trigger backend sorting on initial load

* fix: add unsort icon to indicate that column might be sorted

* test: rollback test changes

* fix: use enums to order by status

* chore: upgrade uic

* refactor: use new seeds tag component (bloom-housing#3597)

* feat: submit for approval flow (bloom-housing#3598)

* fix: cors origin deploy preview issues (bloom-housing#3564)

* fix: update label for monthly minimum income (bloom-housing#3609)

* feat: update label for monthly minimum income

* fix: change string to Minimum Monthly Income

* feat: listings approval superadmin flow (bloom-housing#3611)

* fix: add backend url validation for url fields (bloom-housing#3568)

* fix: add backend url validation for url fields

* fix: validate only if externalUrl should be URL

* fix: use form values for application types on failed form submit

* fix: hide url field when no digital application

* fix: set proper default value to common digital application choice

* fix: add hasHttps decorator for second error variant

* fix: add four and five bedrooms keys to sort array (bloom-housing#3618)

* fix: sort table with listings approval statuses (bloom-housing#3622)

* test: add listings approval cypress tests (bloom-housing#3612)

* feat: listings approval emails (bloom-housing#3600)

* fix: use primary tag variants in partners (bloom-housing#3632)

* fix: amiPercentage being unset on unit edit (bloom-housing#3635)

---------

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Krzysztof Zięcina <kziecina@airnauts.com>
Co-authored-by: Emily Jablonski <65367387+emilyjablonski@users.noreply.github.com>
Co-authored-by: ColinBuyck <53269332+ColinBuyck@users.noreply.github.com>
Co-authored-by: Yazeed Loonat <YazeedLoonat@gmail.com>
  • Loading branch information
6 people authored Sep 6, 2023
1 parent f634ef3 commit b66af87
Show file tree
Hide file tree
Showing 117 changed files with 2,295 additions and 1,343 deletions.
24 changes: 23 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,29 @@ workflows:
working_directory: sites/partners
yarn: true
build: |
echo 'export FEATURE_LISTINGS_APPROVAL=FALSE' >> "$BASH_ENV"
source "$BASH_ENV"
yarn test:backend:core:dbsetup
start: yarn dev:all-cypress
start: |
yarn dev:all-cypress
command: |
npx cypress run --spec cypress/e2e/default/**/*.{js,jsx,ts,tsx}
wait-on: "http://0.0.0.0:3001"
store_artifacts: true
- cypress/run:
name: "cypress-partners-listings-approval"
requires:
- setup
executor: cypress-node
working_directory: sites/partners
yarn: true
build: |
echo 'export FEATURE_LISTINGS_APPROVAL=TRUE' >> "$BASH_ENV"
source "$BASH_ENV"
yarn test:backend:core:dbsetup
start: |
yarn dev:all-cypress
command: |
npx cypress run --spec cypress/e2e/listings-approval/**/*.{js,jsx,ts,tsx}
wait-on: "http://0.0.0.0:3001"
store_artifacts: true
1 change: 1 addition & 0 deletions backend/core/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ GOOGLE_API_KEY=
GOOGLE_API_EMAIL=
PARTNERS_PORTAL_URL=http://localhost:3001
CORS_ORIGINS=["http://localhost:3000", "http://localhost:3001"]
CORS_REGEX=["test1", "test2"]
AFS_PROCESSING_CRON_STRING=0 * * * *
10 changes: 9 additions & 1 deletion backend/core/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,20 @@ import { CatchAllFilter } from "./shared/filters/catch-all-filter"
export function applicationSetup(app: INestApplication) {
const { httpAdapter } = app.get(HttpAdapterHost)
const allowList = process.env.CORS_ORIGINS || []
const allowListRegex = process.env.CORS_REGEX ? JSON.parse(process.env.CORS_REGEX) : []
const regexAllowList = allowListRegex.map((regex) => {
return new RegExp(regex)
})
app.enableCors((req, cb) => {
const options = {
credentials: true,
origin: false,
}
if (allowList.indexOf(req.header("Origin")) !== -1) {

if (
allowList.indexOf(req.header("Origin")) !== -1 ||
regexAllowList.some((regex) => regex.test(req.header("Origin")))
) {
options.origin = true
}
cb(null, options)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { Column, Entity, ManyToOne, OneToMany } from "typeorm"
import { Expose, Type } from "class-transformer"
import { IsBoolean, IsEnum, IsOptional, IsString, MaxLength, ValidateNested } from "class-validator"
import {
IsBoolean,
IsEnum,
IsOptional,
IsString,
IsUrl,
MaxLength,
ValidateIf,
ValidateNested,
} from "class-validator"
import { ValidationsGroupsEnum } from "../../shared/types/validations-groups-enum"
import { AbstractEntity } from "../../shared/entities/abstract.entity"
import { ApiProperty } from "@nestjs/swagger"
import { Listing } from "../../listings/entities/listing.entity"
import { ApplicationMethodType } from "../types/application-method-type-enum"
import { PaperApplication } from "../../paper-applications/entities/paper-application.entity"
import { hasHttps } from "../../shared/decorators/hasHttps.decorator"

@Entity({ name: "application_methods" })
export class ApplicationMethod extends AbstractEntity {
Expand All @@ -29,6 +39,11 @@ export class ApplicationMethod extends AbstractEntity {
@IsOptional({ groups: [ValidationsGroupsEnum.default] })
@IsString({ groups: [ValidationsGroupsEnum.default] })
@MaxLength(4096, { groups: [ValidationsGroupsEnum.default] })
@ValidateIf((o) => o.type === ApplicationMethodType.ExternalLink, {
groups: [ValidationsGroupsEnum.default],
})
@hasHttps({ groups: [ValidationsGroupsEnum.default] })
@IsUrl({ require_protocol: true }, { groups: [ValidationsGroupsEnum.default] })
externalReference?: string | null

@Column({ type: "bool", nullable: true })
Expand Down
152 changes: 152 additions & 0 deletions backend/core/src/email/email.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,35 @@ const translationServiceMock = {
welcomeMessage:
"Thank you for setting up your account on %{appUrl}. It will now be easier for you to start, save, and submit online applications for listings that appear on the site.",
},
requestApproval: {
subject: "Listing Approval Requested",
header: "Listing approval requested",
partnerRequest:
"A Partner has submitted an approval request to publish the %{listingName} listing.",
logInToReviewStart: "Please log into the",
logInToReviewEnd: "and navigate to the listing detail page to review and publish.",
accessListing: "To access the listing after logging in, please click the link below",
},
changesRequested: {
header: "Listing changes requested",
adminRequestStart:
"An administrator is requesting changes to the %{listingName} listing. Please log into the",
adminRequestEnd:
"and navigate to the listing detail page to view the request and edit the listing. To access the listing after logging in, please click the link below",
},
listingApproved: {
header: "New published listing",
adminApproved:
"The %{listingName} listing has been approved and published by an administrator.",
viewPublished: "To view the published listing, please click on the link below",
},
t: {
hello: "Hello",
seeListing: "See Listing",
partnersPortal: "Partners Portal",
viewListing: "View Listing",
editListing: "Edit Listing",
reviewListing: "Review Listing",
},
},
}
Expand Down Expand Up @@ -298,6 +324,132 @@ describe("EmailService", () => {
expect(emailMock.html).toMatch("SPANISH Alameda County Housing Portal is a project of the")
})
})
describe("request approval", () => {
it("should generate html body", async () => {
const emailArr = ["testOne@xample.com", "testTwo@example.com"]
const service = await module.resolve(EmailService)
await service.requestApproval(
user,
{ id: listing.id, name: listing.name },
emailArr,
"http://localhost:3001"
)

expect(sendMock).toHaveBeenCalled()
const emailMock = sendMock.mock.calls[0][0]
expect(emailMock.to).toEqual(emailArr)
expect(emailMock.subject).toEqual("Listing approval requested")
expect(emailMock.html).toMatch(
`<img src="https://res.cloudinary.com/mariposta/image/upload/v1652326298/testing/alameda-portal.png" alt="Alameda County Housing Portal" width="254" height="137" />`
)
expect(emailMock.html).toMatch("Hello,")
expect(emailMock.html).toMatch("Listing approval requested")
expect(emailMock.html).toMatch(
`A Partner has submitted an approval request to publish the ${listing.name} listing.`
)
expect(emailMock.html).toMatch("Please log into the")
expect(emailMock.html).toMatch("Partners Portal")
expect(emailMock.html).toMatch(/http:\/\/localhost:3001/)
expect(emailMock.html).toMatch(
"and navigate to the listing detail page to review and publish."
)
expect(emailMock.html).toMatch(
"To access the listing after logging in, please click the link below"
)
expect(emailMock.html).toMatch("Review Listing")
expect(emailMock.html).toMatch(/http:\/\/localhost:3001\/listings\/Uvbk5qurpB2WI9V6WnNdH/)
expect(emailMock.html).toMatch("Thank you,")
expect(emailMock.html).toMatch("Alameda County Housing Portal")
expect(emailMock.html).toMatch("Alameda County Housing Portal is a project of the")
expect(emailMock.html).toMatch(
"Alameda County - Housing and Community Development (HCD) Department"
)
})
})

describe("changes requested", () => {
it("should generate html body", async () => {
const emailArr = ["testOne@xample.com", "testTwo@example.com"]
const service = await module.resolve(EmailService)
await service.changesRequested(
user,
{ id: listing.id, name: listing.name },
emailArr,
"http://localhost:3001"
)

expect(sendMock).toHaveBeenCalled()
const emailMock = sendMock.mock.calls[0][0]
expect(emailMock.to).toEqual(emailArr)
expect(emailMock.subject).toEqual("Listing changes requested")
expect(emailMock.html).toMatch(
`<img src="https://res.cloudinary.com/mariposta/image/upload/v1652326298/testing/alameda-portal.png" alt="Alameda County Housing Portal" width="254" height="137" />`
)
expect(emailMock.html).toMatch("Listing changes requested")
expect(emailMock.html).toMatch("Hello,")
expect(emailMock.html).toMatch(
`An administrator is requesting changes to the ${listing.name} listing. Please log into the `
)
expect(emailMock.html).toMatch("Partners Portal")
expect(emailMock.html).toMatch(/http:\/\/localhost:3001/)

expect(emailMock.html).toMatch(
" and navigate to the listing detail page to view the request and edit the listing."
)
expect(emailMock.html).toMatch(
"and navigate to the listing detail page to view the request and edit the listing."
)
expect(emailMock.html).toMatch(/http:\/\/localhost:3001/)
expect(emailMock.html).toMatch(
"To access the listing after logging in, please click the link below"
)
expect(emailMock.html).toMatch("Edit Listing")
expect(emailMock.html).toMatch(/http:\/\/localhost:3001\/listings\/Uvbk5qurpB2WI9V6WnNdH/)
expect(emailMock.html).toMatch("Thank you,")
expect(emailMock.html).toMatch("Alameda County Housing Portal")
expect(emailMock.html).toMatch("Alameda County Housing Portal is a project of the")
expect(emailMock.html).toMatch(
"Alameda County - Housing and Community Development (HCD) Department"
)
})
})

describe("published listing", () => {
it("should generate html body", async () => {
const emailArr = ["testOne@xample.com", "testTwo@example.com"]
const service = await module.resolve(EmailService)
await service.listingApproved(
user,
{ id: listing.id, name: listing.name },
emailArr,
"http://localhost:3000"
)

expect(sendMock).toHaveBeenCalled()
const emailMock = sendMock.mock.calls[0][0]
expect(emailMock.to).toEqual(emailArr)
expect(emailMock.subject).toEqual("New published listing")
expect(emailMock.html).toMatch(
`<img src="https://res.cloudinary.com/mariposta/image/upload/v1652326298/testing/alameda-portal.png" alt="Alameda County Housing Portal" width="254" height="137" />`
)
expect(emailMock.html).toMatch("New published listing")
expect(emailMock.html).toMatch("Hello,")
expect(emailMock.html).toMatch(
`The ${listing.name} listing has been approved and published by an administrator.`
)
expect(emailMock.html).toMatch(
"To view the published listing, please click on the link below"
)
expect(emailMock.html).toMatch("View Listing")
expect(emailMock.html).toMatch(/http:\/\/localhost:3000\/listing\/Uvbk5qurpB2WI9V6WnNdH/)
expect(emailMock.html).toMatch("Thank you,")
expect(emailMock.html).toMatch("Alameda County Housing Portal")
expect(emailMock.html).toMatch("Alameda County Housing Portal is a project of the")
expect(emailMock.html).toMatch(
"Alameda County - Housing and Community Development (HCD) Department"
)
})
})

afterAll(async () => {
await module.close()
Expand Down
Loading

0 comments on commit b66af87

Please sign in to comment.