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

[#IP-86] tslint to eslint migration #18

Merged
merged 5 commits into from
Apr 15, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
26 changes: 26 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module.exports = {
"env": {
"browser": true,
"es6": true,
"node": true
},
"ignorePatterns": [
"node_modules",
"generated",
"**/__tests__/*",
"**/__mocks__/*",
"Dangerfile.*",
"*.d.ts"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json",
"sourceType": "module"
},
"extends": [
"@pagopa/eslint-config/strong",
],
"rules": {

}
}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ coverage
/.env
/db-source.json
/db.json

# eslint section
!.eslintrc.js
.eslintcache
2 changes: 1 addition & 1 deletion Dangerfile.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// import custom DangerJS rules
// see http://danger.systems/js
// see https://github.com/teamdigitale/danger-plugin-digitalcitizenship/
// tslint:disable-next-line:prettier
// eslint-disable-next-line prettier/prettier
import checkDangers from 'danger-plugin-digitalcitizenship';

checkDangers();
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
"postversion": "git push && git push --tags",
"start": "node dist/index.js",
"test": "dotenv -e env.example -- jest",
"lint": "tslint --project ."
"lint": "eslint . -c .eslintrc.js --ext .ts,.tsx"
michaeldisaro marked this conversation as resolved.
Show resolved Hide resolved
},
"devDependencies": {
"@pagopa/eslint-config": "^1.1.1",
"@types/express": "^4.17.4",
"@types/jest": "^24.0.13",
"@types/lowdb": "^1.0.9",
Expand All @@ -26,15 +27,14 @@
"danger": "^8.0.0",
"danger-plugin-digitalcitizenship": "*",
"dotenv-cli": "^3.1.0",
"italia-tslint-rules": "*",
"eslint-plugin-prettier": "^3.3.1",
"italia-utils": "^4.1.0",
"jest": "^24.8.0",
"npm-run-all": "^4.1.5",
"prettier": "^1.12.1",
"shx": "^0.3.2",
"supertest": "^4.0.2",
"ts-jest": "^24.0.2",
"tslint": "^5.1.0",
"typescript": "^3.5.0"
},
"dependencies": {
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const emailService = new EmailService(
);

describe("app", () => {
// tslint:disable-next-line:no-let
// eslint-disable-next-line functional/no-let
let app: Express;
beforeAll(async () => {
app = (await newApp(emailService).run()).mapLeft(fail).value;
Expand Down Expand Up @@ -62,7 +62,7 @@ describe("app", () => {
});

describe("PUT installations endpoint", () => {
const endpoint = "/notificationHub/installations";
const endpoint = "/notificationHub/installations/id";
it("should return a 400 error response when the request body is malformed", () => {
return request(app)
.put(endpoint)
Expand Down
140 changes: 70 additions & 70 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Errors } from "io-ts";
import { errorsToReadableMessages } from "italia-ts-commons/lib/reporters";
import * as low from "lowdb";
import { LowdbAsync } from "lowdb";
// tslint:disable-next-line:no-submodule-imports
// eslint-disable-next-line import/no-internal-modules
import * as FileAsync from "lowdb/adapters/FileAsync";
import { CreateOrOverwriteInstallationBody } from "./generated/definitions/CreateOrOverwriteInstallationBody";
import { SendTemplateNotificationBody } from "./generated/definitions/SendTemplateNotificationBody";
Expand All @@ -17,86 +17,24 @@ import { log } from "./utils/logger";
import { getRequestInfo } from "./utils/request";

interface IDbSchema {
installations: ReadonlyArray<CreateOrOverwriteInstallationBody>;
readonly installations: ReadonlyArray<CreateOrOverwriteInstallationBody>;
}

export default function newApp(
emailService: EmailService
): TaskEither<Error, Express> {
// Create Express server
const app = express();

// Express configuration
app.set("port", process.env.PORT || 3000);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.get("/", (_, res) => {
res.json({ message: "The server is up and running" });
});

app.post(
"/:notificationHub/messages",
// Message size cannot be over 64Kb,
// see https://docs.microsoft.com/en-us/rest/api/notificationhubs/send-template-notification#response
bodyParser.json({ limit: "64Kb" }),
(req, res) => {
const endpointInfo = `${req.url} ${req.method}`;
const requestInfo = getRequestInfo(req);
return SendTemplateNotificationBody.decode(req.body)
.mapLeft(errors =>
res.status(getMalformedRequestStatusCode(endpointInfo, errors)).end()
)
.map(() => {
log.info(
"[POST /:notificationHub/messages] Request body: %s",
requestInfo
);
res.status(200).end();
return tryCatch(
() =>
emailService.send({
html: `<pre>${requestInfo}</pre>`,
subject: `[${endpointInfo}]`,
text: requestInfo
}),
toError
)
.mapLeft(error => {
log.error(`[${endpointInfo}] %s`, error);
})
.run();
});
}
);

return tryCatch(() => {
const adapter = new FileAsync<IDbSchema>(getRequiredEnvVar("DB_SOURCE"));
return low(adapter);
}, toError)
.chain(db =>
tryCatch(() => db.defaults({ installations: [] }).write(), toError).map(
() => db
)
)
.map(db => registerInstallationsRoutes(app, db));
}

function getMalformedRequestStatusCode(
const getMalformedRequestStatusCode = (
endpointInfo: string,
errors: Errors
): number {
): number => {
log.info(
`${endpointInfo}Invalid payload. %s`,
errorsToReadableMessages(errors).join(" / ")
);
return 400;
}
};

function registerInstallationsRoutes(
const registerInstallationsRoutes = (
app: Express,
db: LowdbAsync<IDbSchema>
): Express {
): Express => {
app.put("/:notificationHub/installations/:installationId", (req, res) => {
const endpointInfo = `${req.url} ${req.method}`;
const requestInfo = getRequestInfo(req);
Expand Down Expand Up @@ -160,4 +98,66 @@ function registerInstallationsRoutes(
});

return app;
}
};

const newApp = (emailService: EmailService): TaskEither<Error, Express> => {
// Create Express server
const app = express();

// Express configuration
app.set("port", process.env.PORT || 3000);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.get("/", (_, res) => {
res.json({ message: "The server is up and running" });
});

app.post(
"/:notificationHub/messages",
// Message size cannot be over 64Kb,
// see https://docs.microsoft.com/en-us/rest/api/notificationhubs/send-template-notification#response
bodyParser.json({ limit: "64Kb" }),
(req, res) => {
const endpointInfo = `${req.url} ${req.method}`;
const requestInfo = getRequestInfo(req);
return SendTemplateNotificationBody.decode(req.body)
.mapLeft(errors =>
res.status(getMalformedRequestStatusCode(endpointInfo, errors)).end()
)
.map(() => {
log.info(
"[POST /:notificationHub/messages] Request body: %s",
requestInfo
);
res.status(200).end();
return tryCatch(
() =>
emailService.send({
html: `<pre>${requestInfo}</pre>`,
subject: `[${endpointInfo}]`,
text: requestInfo
}),
toError
)
.mapLeft(error => {
log.error(`[${endpointInfo}] %s`, error);
})
.run();
});
}
);

return tryCatch(() => {
const adapter = new FileAsync<IDbSchema>(getRequiredEnvVar("DB_SOURCE"));
return low(adapter);
}, toError)
.chain(db =>
tryCatch(() => db.defaults({ installations: [] }).write(), toError).map(
() => db
)
)
.map(db => registerInstallationsRoutes(app, db));
};

export default newApp;
39 changes: 22 additions & 17 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as fs from "fs";
import * as https from "https";
import { toError } from "fp-ts/lib/Either";
import { tryCatch } from "fp-ts/lib/TaskEither";
import * as fs from "fs";
import newApp from "./app";
import EmailService from "./services/emailService";
import { getRequiredEnvVar, readFile } from "./utils/environment";
import { log } from "./utils/logger";
import * as https from "https";

// read package.json to print some info
const packageJson = JSON.parse(fs.readFileSync("./package.json").toString());
Expand All @@ -26,6 +26,7 @@ const emailService = new EmailService(
}
);

// eslint-disable-next-line @typescript-eslint/no-floating-promises
tryCatch(() => emailService.verifyTransport(), toError)
.mapLeft(error => {
log.error("Error on email service init. %s", error);
Expand All @@ -34,25 +35,29 @@ tryCatch(() => emailService.verifyTransport(), toError)
.chain(() =>
newApp(emailService)
.map(app => {
const options = { key: readFile(
process.env.HTTPS_KEY_PATH || "./certs/key.pem",
"HTTPS certificate"
), cert: readFile(
process.env.HTTPS_CERT_PATH || "./certs/cert.pem",
"HTTPS certificate"
) };
https.createServer(options, app).listen(process.env.PORT || 3000, () => {
log.info(
`${packageJson.name} is running on http://localhost:${app.get(
"port"
)}`
);
})
const options = {
cert: readFile(
process.env.HTTPS_CERT_PATH || "./certs/cert.pem",
"HTTPS certificate"
),
key: readFile(
process.env.HTTPS_KEY_PATH || "./certs/key.pem",
"HTTPS certificate"
)
};
https
.createServer(options, app)
.listen(process.env.PORT || 3000, () => {
log.info(
`${packageJson.name} is running on http://localhost:${app.get(
"port"
)}`
);
});
})
.mapLeft(error => {
log.error("Error on app init. %s", error);
process.exit(1);
})
)
// tslint:disable-next-line:no-floating-promises
.run();
8 changes: 4 additions & 4 deletions src/services/emailService.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import * as nodemailer from "nodemailer";

// tslint:disable-next-line:no-submodule-imports
// eslint-disable-next-line import/no-internal-modules
import SMTPTransport = require("nodemailer/lib/smtp-transport");

export default class EmailService {
private transporter: nodemailer.Transporter;
public constructor(
private readonly transporter: nodemailer.Transporter;
constructor(
transporterConfig: SMTPTransport.Options,
defaults: SMTPTransport.Options
) {
this.transporter = nodemailer.createTransport(transporterConfig, defaults);
}

// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public send(mailOptions: nodemailer.SendMailOptions): Promise<any> {
return this.transporter.sendMail(mailOptions);
}
Expand Down
13 changes: 7 additions & 6 deletions src/utils/environment.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
// Loads all the environment variables from a .env file before using them
// @see https://github.com/motdotla/dotenv/tree/v6.1.0#how-do-i-use-dotenv-with-import
import * as fs from "fs";
import * as dotenv from "dotenv";
dotenv.config();

import * as fs from "fs";
import { log } from "./logger";

/**
* Checks that the environment variables with the provided name is defined,
* if it is undefined logs an error and exits the process
*
* @param varName [string] The name of the required environment variables
*/
export function getRequiredEnvVar(varName: string): string | never {
export const getRequiredEnvVar = (varName: string): string | never => {
const envVar = process.env[varName];
if (envVar === undefined) {
log.error("Required environment variable missing: %s", varName);
return process.exit(1);
}
return envVar;
}
};

/**
* Reads a file from the filesystem..
Expand All @@ -27,8 +28,8 @@ export function getRequiredEnvVar(varName: string): string | never {
* @param type
* @returns {string}
*/
export function readFile(path: string, type: string): string {
export const readFile = (path: string, type: string): string => {
log.info("Reading %s file from %s", type, path);
// eslint-disable-next-line security/detect-non-literal-fs-filename
// eslint-disable-next-line
michaeldisaro marked this conversation as resolved.
Show resolved Hide resolved
return fs.readFileSync(path, "utf-8");
}
};
Loading