mirror of
https://github.com/microsoft/TypeScript-Node-Starter.git
synced 2025-11-08 12:07:34 +00:00
32
README.md
32
README.md
@@ -287,24 +287,24 @@ You'll notice that npm scripts can call each other which makes it easy to compos
|
||||
Below is a list of all the scripts this template has available:
|
||||
|
||||
|
||||
| Npm Script | Description |
|
||||
| Npm Script | Description |
|
||||
| ------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| `start` | Does the same as 'npm run serve'. Can be invoked with `npm start` |
|
||||
| `build` | Full build. Runs ALL build tasks (`build-sass`, `build-ts`, `lint`, `copy-static-assets`) |
|
||||
| `serve` | Runs node on `dist/server.js` which is the apps entry point |
|
||||
| `watch-node` | Runs node with nodemon so the process restarts if it crashes. Used in the main watch task |
|
||||
| `watch` | Runs all watch tasks (TypeScript, Sass, Node). Use this if you're not touching static assets. |
|
||||
| `test` | Runs tests using Jest test runner |
|
||||
| `watch-test` | Runs tests in watch mode |
|
||||
| `build-ts` | Compiles all source `.ts` files to `.js` files in the `dist` folder |
|
||||
| `watch-ts` | Same as `build-ts` but continuously watches `.ts` files and re-compiles when needed |
|
||||
| `build-sass` | Compiles all `.scss` files to `.css` files |
|
||||
| `watch-sass` | Same as `build-sass` but continuously watches `.scss` files and re-compiles when needed |
|
||||
| `lint` | Runs ESLint on project files |
|
||||
| `build-sass` | Compiles all `.scss` files to `.css` files |
|
||||
| `build-ts` | Compiles all source `.ts` files to `.js` files in the `dist` folder |
|
||||
| `build` | Full build. Runs ALL build tasks (`build-sass`, `build-ts`, `lint`, `copy-static-assets`) |
|
||||
| `copy-static-assets` | Calls script that copies JS libs, fonts, and images to dist directory |
|
||||
| `debug` | Performs a full build and then serves the app in watch mode |
|
||||
| `serve-debug` | Runs the app with the --inspect flag |
|
||||
| `watch-debug` | The same as `watch` but includes the --inspect flag so you can attach a debugger |
|
||||
| `lint` | Runs ESLint on project files |
|
||||
| `serve-debug` | Runs the app with the --inspect flag |
|
||||
| `serve` | Runs node on `dist/server.js` which is the apps entry point |
|
||||
| `start` | Does the same as 'npm run serve'. Can be invoked with `npm start` |
|
||||
| `test` | Runs tests using Jest test runner |
|
||||
| `watch-debug` | The same as `watch` but includes the --inspect flag so you can attach a debugger |
|
||||
| `watch-node` | Runs node with nodemon so the process restarts if it crashes. Used in the main watch task |
|
||||
| `watch-sass` | Same as `build-sass` but continuously watches `.scss` files and re-compiles when needed |
|
||||
| `watch-test` | Runs tests in watch mode |
|
||||
| `watch-ts` | Same as `build-ts` but continuously watches `.ts` files and re-compiles when needed |
|
||||
| `watch` | Runs all watch tasks (TypeScript, Sass, Node). Use this if you're not touching static assets. |
|
||||
|
||||
## Type Definition (`.d.ts`) Files
|
||||
TypeScript uses `.d.ts` files to provide types for JavaScript libraries that were not written in TypeScript.
|
||||
@@ -596,7 +596,7 @@ In that file you'll find two sections:
|
||||
| chai | Testing utility library that makes it easier to write tests |
|
||||
| concurrently | Utility that manages multiple concurrent tasks. Used with npm scripts |
|
||||
| jest | Testing library for JavaScript. |
|
||||
| node-sass | Allows to compile .scss files to .css |
|
||||
| sass | Allows to compile .scss files to .css |
|
||||
| nodemon | Utility that automatically restarts node process when it crashes |
|
||||
| supertest | HTTP assertion library. |
|
||||
| ts-jest | A preprocessor with sourcemap support to help use TypeScript with Jest.|
|
||||
|
||||
9246
package-lock.json
generated
9246
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
140
package.json
140
package.json
@@ -9,90 +9,88 @@
|
||||
"author": "Bowden Kelly",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "npm run build-sass && npm run build-ts && npm run lint && npm run copy-static-assets",
|
||||
"build-sass": "node-sass src/public/css/main.scss dist/public/css/main.css",
|
||||
"build-sass": "sass src/public/css/main.scss dist/public/css/main.css",
|
||||
"build-ts": "tsc",
|
||||
"build": "npm run build-sass && npm run build-ts && npm run lint && npm run copy-static-assets",
|
||||
"copy-static-assets": "ts-node copyStaticAssets.ts",
|
||||
"debug": "npm run build && npm run watch-debug",
|
||||
"lint": "tsc --noEmit && eslint \"**/*.{js,ts}\" --quiet --fix",
|
||||
"serve": "node dist/server.js",
|
||||
"serve-debug": "nodemon --inspect dist/server.js",
|
||||
"serve": "node dist/server.js",
|
||||
"start": "npm run serve",
|
||||
"test": "jest --forceExit --coverage --verbose",
|
||||
"watch": "concurrently -k -p \"[{name}]\" -n \"Sass,TypeScript,Node\" -c \"yellow.bold,cyan.bold,green.bold\" \"npm run watch-sass\" \"npm run watch-ts\" \"npm run watch-node\"",
|
||||
"watch-debug": "concurrently -k -p \"[{name}]\" -n \"Sass,TypeScript,Node\" -c \"yellow.bold,cyan.bold,green.bold\" \"npm run watch-sass\" \"npm run watch-ts\" \"npm run serve-debug\"",
|
||||
"watch-node": "nodemon dist/server.js",
|
||||
"watch-sass": "node-sass -w src/public/css/main.scss dist/public/css/main.css",
|
||||
"watch-sass": "sass --watch src/public/css/main.scss dist/public/css/main.css",
|
||||
"watch-test": "npm run test -- --watchAll",
|
||||
"watch-ts": "tsc -w"
|
||||
"watch-ts": "tsc -w",
|
||||
"watch": "concurrently -k -p \"[{name}]\" -n \"Sass,TypeScript,Node\" -c \"yellow.bold,cyan.bold,green.bold\" \"npm run watch-sass\" \"npm run watch-ts\" \"npm run watch-node\""
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "^3.1.0",
|
||||
"bcrypt-nodejs": "^0.0.3",
|
||||
"bluebird": "^3.5.5",
|
||||
"body-parser": "^1.19.0",
|
||||
"compression": "^1.7.4",
|
||||
"connect-mongo": "^3.0.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"errorhandler": "^1.5.1",
|
||||
"express": "^4.17.1",
|
||||
"@types/mongodb": "3.6.5",
|
||||
"async": "3.2.0",
|
||||
"bcrypt-nodejs": "0.0.3",
|
||||
"bluebird": "3.7.2",
|
||||
"body-parser": "1.19.0",
|
||||
"compression": "1.7.4",
|
||||
"connect-mongo": "jdesboeufs/connect-mongo#527f9b6cd3d95d9bcd765c9ef9f2b5705611f9f5",
|
||||
"dotenv": "8.2.0",
|
||||
"errorhandler": "1.5.1",
|
||||
"express": "4.17.1",
|
||||
"express-flash": "0.0.2",
|
||||
"express-session": "^1.16.2",
|
||||
"express-validator": "^6.2.0",
|
||||
"fbgraph": "^1.4.4",
|
||||
"lodash": "^4.17.19",
|
||||
"lusca": "^1.6.1",
|
||||
"mongoose": "^5.7.5",
|
||||
"nodemailer": "^6.3.0",
|
||||
"passport": "^0.4.0",
|
||||
"passport-facebook": "^3.0.0",
|
||||
"passport-local": "^1.0.0",
|
||||
"pug": "^2.0.4",
|
||||
"winston": "^3.2.1"
|
||||
"express-session": "1.17.1",
|
||||
"express-validator": "6.9.2",
|
||||
"fbgraph": "1.4.4",
|
||||
"lodash": "4.17.20",
|
||||
"lusca": "1.6.1",
|
||||
"mongoose": "5.11.15",
|
||||
"nodemailer": "6.4.17",
|
||||
"passport": "0.4.1",
|
||||
"passport-facebook": "3.0.0",
|
||||
"passport-local": "1.0.0",
|
||||
"pug": "3.0.0",
|
||||
"winston": "3.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/async": "^3.0.2",
|
||||
"@types/bcrypt-nodejs": "^0.0.30",
|
||||
"@types/bluebird": "^3.5.27",
|
||||
"@types/body-parser": "^1.17.1",
|
||||
"@types/chai": "^4.2.3",
|
||||
"@types/compression": "^1.0.1",
|
||||
"@types/concurrently": "^4.1.0",
|
||||
"@types/connect-mongo": "^3.0.0",
|
||||
"@types/errorhandler": "^0.0.32",
|
||||
"@types/eslint": "^6.1.1",
|
||||
"@types/express": "^4.17.1",
|
||||
"@types/express-flash": "0.0.1",
|
||||
"@types/express-session": "^1.15.14",
|
||||
"@types/jest": "^24.0.23",
|
||||
"@types/jquery": "^3.3.31",
|
||||
"@types/lodash": "^4.14.141",
|
||||
"@types/lusca": "^1.6.1",
|
||||
"@types/mongoose": "^5.5.18",
|
||||
"@types/node": "^12.7.8",
|
||||
"@types/node-sass": "^4.11.0",
|
||||
"@types/nodemailer": "^6.2.1",
|
||||
"@types/passport": "^1.0.1",
|
||||
"@types/passport-facebook": "^2.1.9",
|
||||
"@types/passport-local": "^1.0.33",
|
||||
"@types/pug": "^2.0.4",
|
||||
"@types/request": "^2.48.3",
|
||||
"@types/request-promise": "^4.1.44",
|
||||
"@types/shelljs": "^0.8.5",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"@types/winston": "^2.4.4",
|
||||
"@typescript-eslint/eslint-plugin": "^2.3.1",
|
||||
"@typescript-eslint/parser": "^2.3.1",
|
||||
"chai": "^4.2.0",
|
||||
"concurrently": "^5.3.0",
|
||||
"eslint": "^6.4.0",
|
||||
"jest": "^24.9.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"nodemon": "^1.19.2",
|
||||
"shelljs": "^0.8.3",
|
||||
"supertest": "^4.0.2",
|
||||
"ts-jest": "^24.1.0",
|
||||
"ts-node": "^8.4.1",
|
||||
"typescript": "^3.6.3"
|
||||
"@types/async": "3.2.5",
|
||||
"@types/bcrypt-nodejs": "0.0.31",
|
||||
"@types/bluebird": "3.5.33",
|
||||
"@types/body-parser": "1.19.0",
|
||||
"@types/chai": "4.2.14",
|
||||
"@types/compression": "1.7.0",
|
||||
"@types/concurrently": "5.2.1",
|
||||
"@types/errorhandler": "1.5.0",
|
||||
"@types/eslint": "7.2.6",
|
||||
"@types/express": "4.17.11",
|
||||
"@types/express-flash": "0.0.2",
|
||||
"@types/express-session": "1.17.3",
|
||||
"@types/jest": "26.0.20",
|
||||
"@types/jquery": "3.5.5",
|
||||
"@types/lodash": "4.14.168",
|
||||
"@types/lusca": "1.6.2",
|
||||
"@types/node": "14.14.25",
|
||||
"@types/nodemailer": "6.4.0",
|
||||
"@types/passport": "1.0.5",
|
||||
"@types/passport-facebook": "2.1.10",
|
||||
"@types/passport-local": "1.0.33",
|
||||
"@types/pug": "2.0.4",
|
||||
"@types/request": "2.48.5",
|
||||
"@types/request-promise": "4.1.47",
|
||||
"@types/shelljs": "0.8.8",
|
||||
"@types/supertest": "2.0.10",
|
||||
"@types/winston": "2.4.4",
|
||||
"@typescript-eslint/eslint-plugin": "4.14.2",
|
||||
"@typescript-eslint/parser": "4.14.2",
|
||||
"chai": "4.3.0",
|
||||
"concurrently": "5.3.0",
|
||||
"eslint": "7.19.0",
|
||||
"jest": "26.6.3",
|
||||
"nodemon": "2.0.7",
|
||||
"sass": "1.32.6",
|
||||
"shelljs": "0.8.4",
|
||||
"supertest": "6.1.3",
|
||||
"ts-jest": "26.5.0",
|
||||
"ts-node": "9.1.1",
|
||||
"typescript": "4.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import * as userController from "./controllers/user";
|
||||
import * as apiController from "./controllers/api";
|
||||
import * as contactController from "./controllers/contact";
|
||||
|
||||
|
||||
// API keys and Passport configuration
|
||||
import * as passportConfig from "./config/passport";
|
||||
|
||||
|
||||
@@ -6,17 +6,18 @@ import _ from "lodash";
|
||||
// import { User, UserType } from '../models/User';
|
||||
import { User, UserDocument } from "../models/User";
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { NativeError } from "mongoose";
|
||||
|
||||
const LocalStrategy = passportLocal.Strategy;
|
||||
const FacebookStrategy = passportFacebook.Strategy;
|
||||
|
||||
passport.serializeUser<any, any>((user, done) => {
|
||||
done(undefined, user.id);
|
||||
passport.serializeUser<any, any>((req, user, done) => {
|
||||
done(undefined, user);
|
||||
});
|
||||
|
||||
passport.deserializeUser((id, done) => {
|
||||
User.findById(id, (err, user) => {
|
||||
done(err, user);
|
||||
User.findById(id, (err: NativeError, user: UserDocument) => {
|
||||
done(err, user.id);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,7 +26,7 @@ passport.deserializeUser((id, done) => {
|
||||
* Sign in using Email and Password.
|
||||
*/
|
||||
passport.use(new LocalStrategy({ usernameField: "email" }, (email, password, done) => {
|
||||
User.findOne({ email: email.toLowerCase() }, (err, user: any) => {
|
||||
User.findOne({ email: email.toLowerCase() }, (err: NativeError, user: UserDocument) => {
|
||||
if (err) { return done(err); }
|
||||
if (!user) {
|
||||
return done(undefined, false, { message: `Email ${email} not found.` });
|
||||
@@ -68,13 +69,13 @@ passport.use(new FacebookStrategy({
|
||||
passReqToCallback: true
|
||||
}, (req: any, accessToken, refreshToken, profile, done) => {
|
||||
if (req.user) {
|
||||
User.findOne({ facebook: profile.id }, (err, existingUser) => {
|
||||
User.findOne({ facebook: profile.id }, (err: NativeError, existingUser: UserDocument) => {
|
||||
if (err) { return done(err); }
|
||||
if (existingUser) {
|
||||
req.flash("errors", { msg: "There is already a Facebook account that belongs to you. Sign in with that account or delete it, then link it with your current account." });
|
||||
done(err);
|
||||
} else {
|
||||
User.findById(req.user.id, (err, user: any) => {
|
||||
User.findById(req.user.id, (err: NativeError, user: UserDocument) => {
|
||||
if (err) { return done(err); }
|
||||
user.facebook = profile.id;
|
||||
user.tokens.push({ kind: "facebook", accessToken });
|
||||
@@ -89,12 +90,12 @@ passport.use(new FacebookStrategy({
|
||||
}
|
||||
});
|
||||
} else {
|
||||
User.findOne({ facebook: profile.id }, (err, existingUser) => {
|
||||
User.findOne({ facebook: profile.id }, (err: NativeError, existingUser: UserDocument) => {
|
||||
if (err) { return done(err); }
|
||||
if (existingUser) {
|
||||
return done(undefined, existingUser);
|
||||
}
|
||||
User.findOne({ email: profile._json.email }, (err, existingEmailUser) => {
|
||||
User.findOne({ email: profile._json.email }, (err: NativeError, existingEmailUser: UserDocument) => {
|
||||
if (err) { return done(err); }
|
||||
if (existingEmailUser) {
|
||||
req.flash("errors", { msg: "There is already an account using this email address. Sign in to that account and link it with Facebook manually from Account Settings." });
|
||||
|
||||
@@ -8,17 +8,18 @@ import { IVerifyOptions } from "passport-local";
|
||||
import { WriteError } from "mongodb";
|
||||
import { check, sanitize, validationResult } from "express-validator";
|
||||
import "../config/passport";
|
||||
import { CallbackError, NativeError } from "mongoose";
|
||||
|
||||
/**
|
||||
* Login page.
|
||||
* @route GET /login
|
||||
*/
|
||||
export const getLogin = (req: Request, res: Response) => {
|
||||
export const getLogin = (req: Request, res: Response): void => {
|
||||
if (req.user) {
|
||||
return res.redirect("/");
|
||||
}
|
||||
res.render("account/login", {
|
||||
title: "Login"
|
||||
title: "Login",
|
||||
});
|
||||
};
|
||||
|
||||
@@ -26,10 +27,9 @@ export const getLogin = (req: Request, res: Response) => {
|
||||
* Sign in using email and password.
|
||||
* @route POST /login
|
||||
*/
|
||||
export const postLogin = async (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postLogin = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
await check("email", "Email is not valid").isEmail().run(req);
|
||||
await check("password", "Password cannot be blank").isLength({min: 1}).run(req);
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
await sanitize("email").normalizeEmail({ gmail_remove_dots: false }).run(req);
|
||||
|
||||
const errors = validationResult(req);
|
||||
@@ -57,7 +57,7 @@ export const postLogin = async (req: Request, res: Response, next: NextFunction)
|
||||
* Log out.
|
||||
* @route GET /logout
|
||||
*/
|
||||
export const logout = (req: Request, res: Response) => {
|
||||
export const logout = (req: Request, res: Response): void => {
|
||||
req.logout();
|
||||
res.redirect("/");
|
||||
};
|
||||
@@ -66,7 +66,7 @@ export const logout = (req: Request, res: Response) => {
|
||||
* Signup page.
|
||||
* @route GET /signup
|
||||
*/
|
||||
export const getSignup = (req: Request, res: Response) => {
|
||||
export const getSignup = (req: Request, res: Response): void => {
|
||||
if (req.user) {
|
||||
return res.redirect("/");
|
||||
}
|
||||
@@ -79,11 +79,10 @@ export const getSignup = (req: Request, res: Response) => {
|
||||
* Create a new local account.
|
||||
* @route POST /signup
|
||||
*/
|
||||
export const postSignup = async (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postSignup = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
await check("email", "Email is not valid").isEmail().run(req);
|
||||
await check("password", "Password must be at least 4 characters long").isLength({ min: 4 }).run(req);
|
||||
await check("confirmPassword", "Passwords do not match").equals(req.body.password).run(req);
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
await sanitize("email").normalizeEmail({ gmail_remove_dots: false }).run(req);
|
||||
|
||||
const errors = validationResult(req);
|
||||
@@ -98,7 +97,7 @@ export const postSignup = async (req: Request, res: Response, next: NextFunction
|
||||
password: req.body.password
|
||||
});
|
||||
|
||||
User.findOne({ email: req.body.email }, (err, existingUser) => {
|
||||
User.findOne({ email: req.body.email }, (err: NativeError, existingUser: UserDocument) => {
|
||||
if (err) { return next(err); }
|
||||
if (existingUser) {
|
||||
req.flash("errors", { msg: "Account with that email address already exists." });
|
||||
@@ -120,7 +119,7 @@ export const postSignup = async (req: Request, res: Response, next: NextFunction
|
||||
* Profile page.
|
||||
* @route GET /account
|
||||
*/
|
||||
export const getAccount = (req: Request, res: Response) => {
|
||||
export const getAccount = (req: Request, res: Response): void => {
|
||||
res.render("account/profile", {
|
||||
title: "Account Management"
|
||||
});
|
||||
@@ -130,9 +129,8 @@ export const getAccount = (req: Request, res: Response) => {
|
||||
* Update profile information.
|
||||
* @route POST /account/profile
|
||||
*/
|
||||
export const postUpdateProfile = async (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postUpdateProfile = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
await check("email", "Please enter a valid email address.").isEmail().run(req);
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
await sanitize("email").normalizeEmail({ gmail_remove_dots: false }).run(req);
|
||||
|
||||
const errors = validationResult(req);
|
||||
@@ -143,14 +141,14 @@ export const postUpdateProfile = async (req: Request, res: Response, next: NextF
|
||||
}
|
||||
|
||||
const user = req.user as UserDocument;
|
||||
User.findById(user.id, (err, user: UserDocument) => {
|
||||
User.findById(user.id, (err: NativeError, user: UserDocument) => {
|
||||
if (err) { return next(err); }
|
||||
user.email = req.body.email || "";
|
||||
user.profile.name = req.body.name || "";
|
||||
user.profile.gender = req.body.gender || "";
|
||||
user.profile.location = req.body.location || "";
|
||||
user.profile.website = req.body.website || "";
|
||||
user.save((err: WriteError) => {
|
||||
user.save((err: WriteError & CallbackError) => {
|
||||
if (err) {
|
||||
if (err.code === 11000) {
|
||||
req.flash("errors", { msg: "The email address you have entered is already associated with an account." });
|
||||
@@ -168,7 +166,7 @@ export const postUpdateProfile = async (req: Request, res: Response, next: NextF
|
||||
* Update current password.
|
||||
* @route POST /account/password
|
||||
*/
|
||||
export const postUpdatePassword = async (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postUpdatePassword = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
await check("password", "Password must be at least 4 characters long").isLength({ min: 4 }).run(req);
|
||||
await check("confirmPassword", "Passwords do not match").equals(req.body.password).run(req);
|
||||
|
||||
@@ -180,10 +178,10 @@ export const postUpdatePassword = async (req: Request, res: Response, next: Next
|
||||
}
|
||||
|
||||
const user = req.user as UserDocument;
|
||||
User.findById(user.id, (err, user: UserDocument) => {
|
||||
User.findById(user.id, (err: NativeError, user: UserDocument) => {
|
||||
if (err) { return next(err); }
|
||||
user.password = req.body.password;
|
||||
user.save((err: WriteError) => {
|
||||
user.save((err: WriteError & CallbackError) => {
|
||||
if (err) { return next(err); }
|
||||
req.flash("success", { msg: "Password has been changed." });
|
||||
res.redirect("/account");
|
||||
@@ -195,7 +193,7 @@ export const postUpdatePassword = async (req: Request, res: Response, next: Next
|
||||
* Delete user account.
|
||||
* @route POST /account/delete
|
||||
*/
|
||||
export const postDeleteAccount = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postDeleteAccount = (req: Request, res: Response, next: NextFunction): void => {
|
||||
const user = req.user as UserDocument;
|
||||
User.remove({ _id: user.id }, (err) => {
|
||||
if (err) { return next(err); }
|
||||
@@ -209,10 +207,10 @@ export const postDeleteAccount = (req: Request, res: Response, next: NextFunctio
|
||||
* Unlink OAuth provider.
|
||||
* @route GET /account/unlink/:provider
|
||||
*/
|
||||
export const getOauthUnlink = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const getOauthUnlink = (req: Request, res: Response, next: NextFunction): void => {
|
||||
const provider = req.params.provider;
|
||||
const user = req.user as UserDocument;
|
||||
User.findById(user.id, (err, user: any) => {
|
||||
User.findById(user.id, (err: NativeError, user: any) => {
|
||||
if (err) { return next(err); }
|
||||
user[provider] = undefined;
|
||||
user.tokens = user.tokens.filter((token: AuthToken) => token.kind !== provider);
|
||||
@@ -228,7 +226,7 @@ export const getOauthUnlink = (req: Request, res: Response, next: NextFunction)
|
||||
* Reset Password page.
|
||||
* @route GET /reset/:token
|
||||
*/
|
||||
export const getReset = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const getReset = (req: Request, res: Response, next: NextFunction): void => {
|
||||
if (req.isAuthenticated()) {
|
||||
return res.redirect("/");
|
||||
}
|
||||
@@ -251,7 +249,7 @@ export const getReset = (req: Request, res: Response, next: NextFunction) => {
|
||||
* Process the reset password request.
|
||||
* @route POST /reset/:token
|
||||
*/
|
||||
export const postReset = async (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postReset = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
await check("password", "Password must be at least 4 characters long.").isLength({ min: 4 }).run(req);
|
||||
await check("confirm", "Passwords must match.").equals(req.body.password).run(req);
|
||||
|
||||
@@ -263,7 +261,7 @@ export const postReset = async (req: Request, res: Response, next: NextFunction)
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function resetPassword(done: Function) {
|
||||
function resetPassword(done: (err: any, user: UserDocument) => void) {
|
||||
User
|
||||
.findOne({ passwordResetToken: req.params.token })
|
||||
.where("passwordResetExpires").gt(Date.now())
|
||||
@@ -284,7 +282,7 @@ export const postReset = async (req: Request, res: Response, next: NextFunction)
|
||||
});
|
||||
});
|
||||
},
|
||||
function sendResetPasswordEmail(user: UserDocument, done: Function) {
|
||||
function sendResetPasswordEmail(user: UserDocument, done: (err: Error) => void) {
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: "SendGrid",
|
||||
auth: {
|
||||
@@ -313,7 +311,7 @@ export const postReset = async (req: Request, res: Response, next: NextFunction)
|
||||
* Forgot Password page.
|
||||
* @route GET /forgot
|
||||
*/
|
||||
export const getForgot = (req: Request, res: Response) => {
|
||||
export const getForgot = (req: Request, res: Response): void => {
|
||||
if (req.isAuthenticated()) {
|
||||
return res.redirect("/");
|
||||
}
|
||||
@@ -326,9 +324,8 @@ export const getForgot = (req: Request, res: Response) => {
|
||||
* Create a random token, then the send user an email with a reset link.
|
||||
* @route POST /forgot
|
||||
*/
|
||||
export const postForgot = async (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postForgot = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
await check("email", "Please enter a valid email address.").isEmail().run(req);
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
await sanitize("email").normalizeEmail({ gmail_remove_dots: false }).run(req);
|
||||
|
||||
const errors = validationResult(req);
|
||||
@@ -339,14 +336,14 @@ export const postForgot = async (req: Request, res: Response, next: NextFunction
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function createRandomToken(done: Function) {
|
||||
function createRandomToken(done: (err: Error, token: string) => void) {
|
||||
crypto.randomBytes(16, (err, buf) => {
|
||||
const token = buf.toString("hex");
|
||||
done(err, token);
|
||||
});
|
||||
},
|
||||
function setRandomToken(token: AuthToken, done: Function) {
|
||||
User.findOne({ email: req.body.email }, (err, user: any) => {
|
||||
function setRandomToken(token: AuthToken, done: (err: NativeError | WriteError, token?: AuthToken, user?: UserDocument) => void) {
|
||||
User.findOne({ email: req.body.email }, (err: NativeError, user: any) => {
|
||||
if (err) { return done(err); }
|
||||
if (!user) {
|
||||
req.flash("errors", { msg: "Account with that email address does not exist." });
|
||||
@@ -359,7 +356,7 @@ export const postForgot = async (req: Request, res: Response, next: NextFunction
|
||||
});
|
||||
});
|
||||
},
|
||||
function sendForgotPasswordEmail(token: AuthToken, user: UserDocument, done: Function) {
|
||||
function sendForgotPasswordEmail(token: AuthToken, user: UserDocument, done: (err: Error) => void) {
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: "SendGrid",
|
||||
auth: {
|
||||
|
||||
@@ -23,32 +23,35 @@ export type UserDocument = mongoose.Document & {
|
||||
gravatar: (size: number) => string;
|
||||
};
|
||||
|
||||
type comparePasswordFunction = (candidatePassword: string, cb: (err: any, isMatch: any) => {}) => void;
|
||||
type comparePasswordFunction = (candidatePassword: string, cb: (err: any, isMatch: any) => void) => void;
|
||||
|
||||
export interface AuthToken {
|
||||
accessToken: string;
|
||||
kind: string;
|
||||
}
|
||||
|
||||
const userSchema = new mongoose.Schema({
|
||||
email: { type: String, unique: true },
|
||||
password: String,
|
||||
passwordResetToken: String,
|
||||
passwordResetExpires: Date,
|
||||
|
||||
facebook: String,
|
||||
twitter: String,
|
||||
google: String,
|
||||
tokens: Array,
|
||||
|
||||
profile: {
|
||||
name: String,
|
||||
gender: String,
|
||||
location: String,
|
||||
website: String,
|
||||
picture: String
|
||||
}
|
||||
}, { timestamps: true });
|
||||
const userSchema = new mongoose.Schema<UserDocument>(
|
||||
{
|
||||
email: { type: String, unique: true },
|
||||
password: String,
|
||||
passwordResetToken: String,
|
||||
passwordResetExpires: Date,
|
||||
|
||||
facebook: String,
|
||||
twitter: String,
|
||||
google: String,
|
||||
tokens: Array,
|
||||
|
||||
profile: {
|
||||
name: String,
|
||||
gender: String,
|
||||
location: String,
|
||||
website: String,
|
||||
picture: String
|
||||
}
|
||||
},
|
||||
{ timestamps: true },
|
||||
);
|
||||
|
||||
/**
|
||||
* Password hash middleware.
|
||||
|
||||
12
src/types/express-session-types.d.ts
vendored
Normal file
12
src/types/express-session-types.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Naming this file express-session.d.ts causes imports from "express-session"
|
||||
* to reference this file and not the node_modules package.
|
||||
*/
|
||||
|
||||
import session from "express-session-types";
|
||||
|
||||
declare module "express-session" {
|
||||
export interface SessionData {
|
||||
returnTo: string;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user