Skip to content
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

1555 Build endpoint for sending project updates #1616

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { DocumentModule } from "./document/document.module";
import { CrmModule } from "./crm/crm.module";
import { ZoningResolutionsModule } from "./zoning-resolutions/zoning-resolutions.module";
import { SubscriberModule } from "./subscriber/subscriber.module";
import { SendUpdateModule } from "./send-update/send-update.module";

@Module({
providers: [
Expand All @@ -36,7 +37,8 @@ import { SubscriberModule } from "./subscriber/subscriber.module";
AssignmentModule,
DocumentModule,
ZoningResolutionsModule,
SubscriberModule
SubscriberModule,
SendUpdateModule
],
controllers: [AppController]
})
Expand Down
17 changes: 17 additions & 0 deletions server/src/listserv/listserv-auth.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { ListservAuthService } from './listserv-auth.service';

@Injectable()
export class ListservAuthGuard implements CanActivate {
constructor(
private listservAuthService: ListservAuthService
) {}

canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
return this.listservAuthService.validateUser(request.headers.authorization);
}
}
9 changes: 9 additions & 0 deletions server/src/listserv/listserv-auth.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { ListservAuthService } from './listserv-auth.service';
import { ConfigModule } from '../config/config.module';

@Module({
imports: [ConfigModule],
providers: [ListservAuthService],
})
export class ListservAuthModule {}
19 changes: 19 additions & 0 deletions server/src/listserv/listserv-auth.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Injectable } from '@nestjs/common';
import { ConfigService } from "../config/config.service";

@Injectable()
export class ListservAuthService {
password = "";
constructor(
private readonly config: ConfigService,
) {
this.password = this.config.get("LISTSERV_BASE64");
}

validateUser(password: string) {
if (`Basic ${this.password}` === password) {
return true;
}
return false;
}
}
120 changes: 120 additions & 0 deletions server/src/send-update/send-update.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { Controller, Param, Post, Req, Res } from "@nestjs/common";
import { ConfigService } from "../config/config.service";
import { SendUpdateService } from "./send-update.service";
import { ProjectService } from "../project/project.service";
import { ListservAuthService } from "../listserv/listserv-auth.service";
import { UseGuards } from "@nestjs/common";
import { ListservAuthGuard } from "src/listserv/listserv-auth.guard";
import { Request } from "express";

@Controller()
@UseGuards(ListservAuthGuard)
export class SendUpdateController {
apiKey = "";
list = "";
sendgridEnvironment = "";

constructor(
private readonly config: ConfigService,
private readonly sendUpdateService: SendUpdateService,
private readonly projectService: ProjectService,
private readonly listservAuthService: ListservAuthService
) {
this.apiKey = this.config.get("SENDGRID_API_KEY");
this.list = this.config.get("SENDGRID_LIST");
this.sendgridEnvironment = this.config.get("SENDGRID_ENVIRONMENT")
}

@Post("/projects/:id/send-update")
async sendUpdate(@Param() params, @Req() request: Request, @Res() response) {
const project = await this.projectService.findOneByName(params.id);
dhochbaum-dcp marked this conversation as resolved.
Show resolved Hide resolved
// If no project is found, projectService returns HTTP error automatically, and this function does not continue

var segments = project["data"]["attributes"]["dcp-borough"] === "Citywide" ? [{ name: "CW", envSegment: `zap${this.sendgridEnvironment === "production" ? "_production_" : "_staging_"}CW`, segmentId: "" }] : [];

if(project["data"]["attributes"]["dcp-validatedcommunitydistricts"]) {
project["data"]["attributes"]["dcp-validatedcommunitydistricts"].split(",").forEach(element => {
segments.push({ name: element, envSegment: `zap${this.sendgridEnvironment === "production" ? "_production_" : "_staging_"}${element}`, segmentId: "" })
});
}

if (!segments.length) {
response.status(400).send({
isError: true,
project,
error: "No associated segments found."
})
return;
}

for (const segment of segments) {
const segmentIdResult = await this.sendUpdateService.getSegmentId(segment.envSegment);
if(segmentIdResult.isError) {
response.status(500).send(segmentIdResult);
return;
}
segment.segmentId = segmentIdResult.segmentId;
}

var creationUpdates = [];
var sendUpdates = [];

const boros = {
K: 'Brooklyn',
X: 'Bronx',
M: 'Manhattan',
Q: 'Queens',
R: 'Staten Island',
};

for (const segment of segments) {
const emailData = {
"domain": this.sendgridEnvironment === "production" ? "zap.planning.nyc.gov" : "zap-staging.planninglabs.nyc",
"id": params.id,
"name": project["data"]["attributes"]["dcp-projectname"],
"borocd": segment.name === "CW" ? "Citywide" : `${boros[segment.name.slice(0,1)]} CD ${parseInt(segment.name.slice(1), 10)}`,
"status": project["data"]["attributes"]["dcp-publicstatus"],
"date": new Date().toLocaleDateString(),
"additionalpublicinformation": project["data"]["attributes"]["dcp-additionalpublicinformation"],
"dcpIsApplicant": project["data"]["attributes"]["dcp-applicant-customer-value"] === "DCP - Department of City Planning (NYC)",
"spansMoreThanOneCD": (project["data"]["attributes"]["dcp-validatedcommunitydistricts"] && (project["data"]["attributes"]["dcp-validatedcommunitydistricts"].split(",").length > 1))
}

const emailHtml = this.sendUpdateService.createProjectUpdateContent(emailData);

const createUpdate = await this.sendUpdateService.createSingleSendProjectUpdate(params.id, emailHtml, segment.segmentId);

if (createUpdate.isError) {
response.status(createUpdate.code).send({
isError: true,
project,
createUpdate
})
return;
}

const sendUpdate = await this.sendUpdateService.scheduleSingleSendProjectUpdate(createUpdate["0"]["body"]["id"]);

if (sendUpdate.isError) {
response.status(sendUpdate.code).send({
isError: true,
project,
createUpdate,
sendUpdate
})
return;
}

creationUpdates.push(createUpdate);
sendUpdates.push(sendUpdate);
}

response.status(201).send({
isError: false,
project,
creationUpdates,
sendUpdates
});
return;
}
}
36 changes: 36 additions & 0 deletions server/src/send-update/send-update.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Module } from "@nestjs/common";
import { SendUpdateController } from "./send-update.controller";
import { SendUpdateService } from "./send-update.service";
import { ProjectService } from "../project/project.service";
import { Client } from "@sendgrid/client";
import { MailService } from "@sendgrid/mail";
import { ProjectModule } from "../project/project.module";
import { ArtifactModule } from "../artifact/artifact.module";
import { PackageModule } from "../package/package.module";
import { ConfigModule } from "../config/config.module";
import { CartoModule } from "../carto/carto.module";
import { CrmModule } from "../crm/crm.module";
import { DocumentModule } from "../document/document.module";
import { DispositionModule } from "../disposition/disposition.module";
import { GeometryService } from "../project/geometry/geometry.service";
import { ListservAuthModule } from "../listserv/listserv-auth.module";
import { ListservAuthService } from "../listserv/listserv-auth.service";

@Module({
imports: [
ConfigModule,
ProjectModule,
ArtifactModule,
PackageModule,
ConfigModule,
CartoModule,
CrmModule,
DispositionModule,
DocumentModule,
ListservAuthModule,
],
providers: [SendUpdateService, Client, MailService, ProjectService, GeometryService, ListservAuthService],
exports: [SendUpdateService],
controllers: [SendUpdateController]
})
export class SendUpdateModule {}
Loading
Loading