Skip to content

Commit

Permalink
Merge pull request #18 from pagopa/ip-86-tslint2eslint
Browse files Browse the repository at this point in the history
[#IP-86] tslint to eslint migration
  • Loading branch information
michaeldisaro committed Apr 15, 2021
2 parents 47ed500 + 8d9da61 commit de70088
Show file tree
Hide file tree
Showing 13 changed files with 1,511 additions and 293 deletions.
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"
},
"devDependencies": {
"@pagopa/eslint-config": "^1.3.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
12 changes: 6 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,7 @@ 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
return fs.readFileSync(path, "utf-8");
}
};
Loading

0 comments on commit de70088

Please sign in to comment.