Merge branch 'master' into master
This commit is contained in:
Коммит
a548d8876a
|
@ -37,3 +37,5 @@ Thumbs.db
|
|||
# Ignore built ts files
|
||||
dist/**/*
|
||||
|
||||
# ignore yarn.lock
|
||||
yarn.lock
|
||||
|
|
26
.travis.yml
26
.travis.yml
|
@ -1,12 +1,14 @@
|
|||
|
||||
{
|
||||
"language": "node_js",
|
||||
"node_js": "8",
|
||||
"services": [
|
||||
"mongodb"
|
||||
],
|
||||
"script": [
|
||||
"npm run build",
|
||||
"npm run test"
|
||||
]
|
||||
}
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- 8
|
||||
- 9
|
||||
- 10
|
||||
services:
|
||||
- mongodb
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
script:
|
||||
- npm run build
|
||||
- npm run test
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"eg2.tslint",
|
||||
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||
"ms-azuretools.vscode-cosmosdb",
|
||||
"streetsidesoftware.code-spell-checker"
|
||||
]
|
||||
}
|
|
@ -10,9 +10,8 @@
|
|||
"tslint.ignoreDefinitionFiles": false,
|
||||
"tslint.autoFixOnSave": true,
|
||||
"tslint.exclude": "**/node_modules/**/*",
|
||||
"cSpell.words": [
|
||||
"csrf",
|
||||
"definitelytyped",
|
||||
"promisified"
|
||||
]
|
||||
"appService.zipIgnorePattern": [
|
||||
".vscode{,/**}"
|
||||
],
|
||||
"appService.deploySubpath": ""
|
||||
}
|
26
README.md
26
README.md
|
@ -7,7 +7,7 @@
|
|||
![image](https://user-images.githubusercontent.com/820883/36764267-abbdb7f8-1be0-11e8-9678-2a9ea448d7f8.png)
|
||||
|
||||
The main purpose of this repository is to show a good end-to-end project setup and workflow for writing Node code in TypeScript.
|
||||
I will try to keep this as up-to-date as possible, but community contributions and recommendations for improvements are encouraged and will be most welcome.
|
||||
We will try to keep this as up-to-date as possible, but community contributions and recommendations for improvements are encouraged and will be most welcome.
|
||||
|
||||
|
||||
# Pre-reqs
|
||||
|
@ -45,7 +45,7 @@ npm start
|
|||
Or, if you're using VS Code, you can use `cmd + shift + b` to run the default build task (which is mapped to `npm run build`), and then you can use the command palette (`cmd + shift + p`) and select `Tasks: Run Task` > `npm: start` to run `npm start` for you.
|
||||
|
||||
> **Note on editors!** - TypeScript has great support in [every editor](http://www.typescriptlang.org/index.html#download-links), but this project has been pre-configured for use with [VS Code](https://code.visualstudio.com/).
|
||||
Throughout the README I'll try to call out specific places where VS Code really shines or where this project has been setup to take advantage of specific features.
|
||||
Throughout the README We will try to call out specific places where VS Code really shines or where this project has been setup to take advantage of specific features.
|
||||
|
||||
Finally, navigate to `http://localhost:3000` and you should see the template being served and rendered locally!
|
||||
|
||||
|
@ -53,7 +53,7 @@ Finally, navigate to `http://localhost:3000` and you should see the template bei
|
|||
There are many ways to deploy an Node app, and in general, nothing about the deployment process changes because you're using TypeScript.
|
||||
In this section, I'll walk you through how to deploy this app to Azure App Service using the extensions available in VS Code because I think it is the easiest and fastest way to get started, as well as the most friendly workflow from a developer's perspective.
|
||||
|
||||
## Pre-reqs
|
||||
## Prerequisites
|
||||
- [**Azure account**](https://azure.microsoft.com/en-us/free/) - If you don't have one, you can sign up for free.
|
||||
The Azure free tier gives you plenty of resources to play around with including up to 10 App Service instances, which is what we will be using.
|
||||
- [**VS Code**](https://code.visualstudio.com/) - We'll be using the interface provided by VS Code to quickly deploy our app.
|
||||
|
@ -64,7 +64,7 @@ The easiest way to achieve this is by using a managed cloud database.
|
|||
There are many different providers, but the easiest one to get started with is [MongoLab](#mlab).
|
||||
|
||||
### <a name="mlab"></a> Create a managed MongoDB with MongoLab
|
||||
1. Navigate to [MongoLab's Website](https://mlab.com/), sign up for a free account, and then log in.
|
||||
1. Navigate to [mLab's Website](https://mlab.com/), sign up for a free account, and then log in.
|
||||
2. In the **MongoDB Deployments** section, click the **Create New** button.
|
||||
3. Select any provider (I recommend **Microsoft Azure** as it provides an easier path to upgrading to globally distributed instances later).
|
||||
4. Select **Sandbox** to keep it free unless you know what you're doing, and hit **Continue**.
|
||||
|
@ -104,7 +104,7 @@ You can confirm that everything worked by seeing your Azure subscription listed
|
|||
Additionally you should see the email associated with your account listed in the status bar at the bottom of VS Code.
|
||||
|
||||
### Build the app
|
||||
Building the app locally is required for before a zip deploy because the App Service won't execute build tasks.
|
||||
Building the app locally is required before a zip deploy because the App Service won't execute build tasks.
|
||||
Build the app however you normally would:
|
||||
- `ctrl + shift + b` - kicks off default build in VS Code
|
||||
- execute `npm run build` from a terminal window
|
||||
|
@ -143,7 +143,7 @@ Deployment can fail for various reasons, if you get stuck with a page that says
|
|||
|
||||
# TypeScript + Node
|
||||
In the next few sections I will call out everything that changes when adding TypeScript to an Express project.
|
||||
Note that all of this has already been setup for this project, but feel free to use this as a reference for converting other Node.js project to TypeScript.
|
||||
Note that all of this has already been setup for this project, but feel free to use this as a reference for converting other Node.js projects to TypeScript.
|
||||
|
||||
## Getting TypeScript
|
||||
TypeScript itself is simple to add to any project with `npm`.
|
||||
|
@ -176,7 +176,7 @@ The full folder structure of this app is explained below:
|
|||
| **src/public** | Static assets that will be used client side |
|
||||
| **src/types** | Holds .d.ts files not found on DefinitelyTyped. Covered more in this [section](#type-definition-dts-files) |
|
||||
| **src**/server.ts | Entry point to your express app |
|
||||
| **test** | Contains your tests. Seperate from source because there is a different build process. |
|
||||
| **test** | Contains your tests. Separate from source because there is a different build process. |
|
||||
| **views** | Views define how your app renders on the client. In this case we're using pug |
|
||||
| .env.example | API keys, tokens, passwords, database URI. Clone this, but don't check it in to public repos. |
|
||||
| .travis.yml | Used to configure Travis CI build |
|
||||
|
@ -188,7 +188,7 @@ The full folder structure of this app is explained below:
|
|||
| tslint.json | Config settings for TSLint code style checking |
|
||||
|
||||
## Building the project
|
||||
It is rare for JavaScript projects not to have some kind of build pipeline these days, however Node projects typically have the least amount build configuration.
|
||||
It is rare for JavaScript projects not to have some kind of build pipeline these days. However, Node projects typically have the least amount of build configuration.
|
||||
Because of this I've tried to keep the build as simple as possible.
|
||||
If you're concerned about compile time, the main watch task takes ~2s to refresh.
|
||||
|
||||
|
@ -229,7 +229,7 @@ Let's dissect this project's `tsconfig.json`, starting with the `compilerOptions
|
|||
|
||||
|
||||
|
||||
The rest of the file define the TypeScript project context.
|
||||
The rest of the file defines the TypeScript project context.
|
||||
The project context is basically a set of options that determine which files are compiled when the compiler is invoked with a specific `tsconfig.json`.
|
||||
In this case, we use the following to define our project context:
|
||||
```json
|
||||
|
@ -363,7 +363,7 @@ Source maps allow you to drop break points in your TypeScript source code and ha
|
|||
> **Note!** - Source maps aren't specific to TypeScript.
|
||||
Anytime JavaScript is transformed (transpiled, compiled, optimized, minified, etc) you need source maps so that the code that is executed at runtime can be _mapped_ back to the source that generated it.
|
||||
|
||||
The best part of source maps is when configured correctly, you don't even know they exist! So let's take a look at how we do that in this project.
|
||||
The best part of source maps is, when configured correctly, you don't even know they exist! So let's take a look at how we do that in this project.
|
||||
|
||||
#### Configuring source maps
|
||||
First you need to make sure your `tsconfig.json` has source map generation enabled:
|
||||
|
@ -523,7 +523,7 @@ In that file you'll find two sections:
|
|||
| node-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 wit Jest.|
|
||||
| ts-jest | A preprocessor with sourcemap support to help use TypeScript with Jest.|
|
||||
| ts-node | Enables directly running TS files. Used to run `copy-static-assets.ts` |
|
||||
| tslint | Linter (similar to ESLint) for TypeScript files |
|
||||
| typescript | JavaScript compiler/type checker that boosts JavaScript productivity |
|
||||
|
@ -532,3 +532,7 @@ To install or update these dependencies you can use `npm install` or `npm update
|
|||
|
||||
# Hackathon Starter Project
|
||||
A majority of this quick start's content was inspired or adapted from Sahat's excellent [Hackathon Starter project](https://github.com/sahat/hackathon-starter).
|
||||
|
||||
## License
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the [MIT](LICENSE.txt) License.
|
|
@ -1,7 +1,7 @@
|
|||
module.exports = {
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsConfigFile: 'tsconfig.json'
|
||||
tsConfig: 'tsconfig.json'
|
||||
}
|
||||
},
|
||||
moduleFileExtensions: [
|
||||
|
@ -9,10 +9,10 @@ module.exports = {
|
|||
'js'
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.(ts|tsx)$': './node_modules/ts-jest/preprocessor.js'
|
||||
'^.+\\.(ts|tsx)$': 'ts-jest'
|
||||
},
|
||||
testMatch: [
|
||||
'**/test/**/*.test.(ts|js)'
|
||||
],
|
||||
testEnvironment: 'node'
|
||||
};
|
||||
};
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
18
package.json
18
package.json
|
@ -42,13 +42,13 @@
|
|||
"fbgraph": "^1.4.1",
|
||||
"lodash": "^4.17.5",
|
||||
"lusca": "^1.5.2",
|
||||
"mongoose": "^4.13.11",
|
||||
"mongoose": "^5.4.2",
|
||||
"nodemailer": "^4.4.1",
|
||||
"passport": "^0.4.0",
|
||||
"passport-facebook": "^2.1.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"pug": "^2.0.0-rc.4",
|
||||
"request": "^2.83.0",
|
||||
"pug": "^2.0.3",
|
||||
"request": "^2.88.0",
|
||||
"request-promise": "^4.2.2",
|
||||
"winston": "^2.4.0"
|
||||
},
|
||||
|
@ -64,7 +64,7 @@
|
|||
"@types/express": "^4.11.1",
|
||||
"@types/express-session": "^1.15.8",
|
||||
"@types/jest": "^22.1.3",
|
||||
"@types/jquery": "^3.2.17",
|
||||
"@types/jquery": "^3.3.29",
|
||||
"@types/lodash": "^4.14.91",
|
||||
"@types/lusca": "^1.5.0",
|
||||
"@types/mongodb": "^3.0.5",
|
||||
|
@ -81,14 +81,14 @@
|
|||
"@types/winston": "^2.3.7",
|
||||
"chai": "^4.1.2",
|
||||
"concurrently": "^3.5.1",
|
||||
"jest": "^22.0.4",
|
||||
"node-sass": "^4.7.2",
|
||||
"nodemon": "^1.13.0",
|
||||
"jest": "^24.0.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"nodemon": "^1.18.10",
|
||||
"shelljs": "^0.8.1",
|
||||
"supertest": "^3.0.0",
|
||||
"ts-jest": "^22.0.4",
|
||||
"ts-jest": "^24.0.0",
|
||||
"ts-node": "^5.0.0",
|
||||
"tslint": "^5.9.1",
|
||||
"typescript": "^2.7.2"
|
||||
"typescript": "^3.4.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ import express from "express";
|
|||
import compression from "compression"; // compresses requests
|
||||
import session from "express-session";
|
||||
import bodyParser from "body-parser";
|
||||
import logger from "./util/logger";
|
||||
import lusca from "lusca";
|
||||
import dotenv from "dotenv";
|
||||
import mongo from "connect-mongo";
|
||||
|
@ -35,7 +34,8 @@ const app = express();
|
|||
// Connect to MongoDB
|
||||
const mongoUrl = MONGODB_URI;
|
||||
(<any>mongoose).Promise = bluebird;
|
||||
mongoose.connect(mongoUrl, {useMongoClient: true}).then(
|
||||
|
||||
mongoose.connect(mongoUrl, { useMongoClient: true }).then(
|
||||
() => { /** ready to use. The `mongoose.connect()` promise resolves to undefined. */ },
|
||||
).catch(err => {
|
||||
console.log("MongoDB connection error. Please make sure MongoDB is running. " + err);
|
||||
|
@ -122,4 +122,4 @@ app.get("/auth/facebook/callback", passport.authenticate("facebook", { failureRe
|
|||
res.redirect(req.session.returnTo || "/");
|
||||
});
|
||||
|
||||
export default app;
|
||||
export default app;
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import passport from "passport";
|
||||
import request from "request";
|
||||
import passportLocal from "passport-local";
|
||||
import passportFacebook from "passport-facebook";
|
||||
import _ from "lodash";
|
||||
|
||||
// import { User, UserType } from '../models/User';
|
||||
import { default as User } from "../models/User";
|
||||
import { User } from "../models/User";
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
|
||||
const LocalStrategy = passportLocal.Strategy;
|
||||
|
@ -121,7 +120,7 @@ passport.use(new FacebookStrategy({
|
|||
/**
|
||||
* Login Required middleware.
|
||||
*/
|
||||
export let isAuthenticated = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const isAuthenticated = (req: Request, res: Response, next: NextFunction) => {
|
||||
if (req.isAuthenticated()) {
|
||||
return next();
|
||||
}
|
||||
|
@ -131,7 +130,7 @@ export let isAuthenticated = (req: Request, res: Response, next: NextFunction) =
|
|||
/**
|
||||
* Authorization Required middleware.
|
||||
*/
|
||||
export let isAuthorized = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const isAuthorized = (req: Request, res: Response, next: NextFunction) => {
|
||||
const provider = req.path.split("/").slice(-1)[0];
|
||||
|
||||
if (_.find(req.user.tokens, { kind: provider })) {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
import async from "async";
|
||||
import request from "request";
|
||||
import graph from "fbgraph";
|
||||
import { Response, Request, NextFunction } from "express";
|
||||
|
||||
|
@ -10,7 +8,7 @@ import { Response, Request, NextFunction } from "express";
|
|||
* GET /api
|
||||
* List of API examples.
|
||||
*/
|
||||
export let getApi = (req: Request, res: Response) => {
|
||||
export const getApi = (req: Request, res: Response) => {
|
||||
res.render("api/index", {
|
||||
title: "API Examples"
|
||||
});
|
||||
|
@ -20,7 +18,7 @@ export let getApi = (req: Request, res: Response) => {
|
|||
* GET /api/facebook
|
||||
* Facebook API example.
|
||||
*/
|
||||
export let getFacebook = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const getFacebook = (req: Request, res: Response, next: NextFunction) => {
|
||||
const token = req.user.tokens.find((token: any) => token.kind === "facebook");
|
||||
graph.setAccessToken(token.accessToken);
|
||||
graph.get(`${req.user.facebook}?fields=id,name,email,first_name,last_name,gender,link,locale,timezone`, (err: Error, results: graph.FacebookUser) => {
|
||||
|
|
|
@ -13,7 +13,7 @@ const transporter = nodemailer.createTransport({
|
|||
* GET /contact
|
||||
* Contact form page.
|
||||
*/
|
||||
export let getContact = (req: Request, res: Response) => {
|
||||
export const getContact = (req: Request, res: Response) => {
|
||||
res.render("contact", {
|
||||
title: "Contact"
|
||||
});
|
||||
|
@ -23,7 +23,7 @@ export let getContact = (req: Request, res: Response) => {
|
|||
* POST /contact
|
||||
* Send a contact form via Nodemailer.
|
||||
*/
|
||||
export let postContact = (req: Request, res: Response) => {
|
||||
export const postContact = (req: Request, res: Response) => {
|
||||
req.assert("name", "Name cannot be blank").notEmpty();
|
||||
req.assert("email", "Email is not valid").isEmail();
|
||||
req.assert("message", "Message cannot be blank").notEmpty();
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Request, Response } from "express";
|
|||
* GET /
|
||||
* Home page.
|
||||
*/
|
||||
export let index = (req: Request, res: Response) => {
|
||||
export const index = (req: Request, res: Response) => {
|
||||
res.render("home", {
|
||||
title: "Home"
|
||||
});
|
||||
|
|
|
@ -2,19 +2,18 @@ import async from "async";
|
|||
import crypto from "crypto";
|
||||
import nodemailer from "nodemailer";
|
||||
import passport from "passport";
|
||||
import { default as User, UserModel, AuthToken } from "../models/User";
|
||||
import { User, UserDocument, AuthToken } from "../models/User";
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { IVerifyOptions } from "passport-local";
|
||||
import { WriteError } from "mongodb";
|
||||
import request from "express-validator";
|
||||
import "../config/passport";
|
||||
|
||||
|
||||
/**
|
||||
* GET /login
|
||||
* Login page.
|
||||
*/
|
||||
export let getLogin = (req: Request, res: Response) => {
|
||||
export const getLogin = (req: Request, res: Response) => {
|
||||
if (req.user) {
|
||||
return res.redirect("/");
|
||||
}
|
||||
|
@ -27,7 +26,7 @@ export let getLogin = (req: Request, res: Response) => {
|
|||
* POST /login
|
||||
* Sign in using email and password.
|
||||
*/
|
||||
export let postLogin = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postLogin = (req: Request, res: Response, next: NextFunction) => {
|
||||
req.assert("email", "Email is not valid").isEmail();
|
||||
req.assert("password", "Password cannot be blank").notEmpty();
|
||||
req.sanitize("email").normalizeEmail({ gmail_remove_dots: false });
|
||||
|
@ -39,7 +38,7 @@ export let postLogin = (req: Request, res: Response, next: NextFunction) => {
|
|||
return res.redirect("/login");
|
||||
}
|
||||
|
||||
passport.authenticate("local", (err: Error, user: UserModel, info: IVerifyOptions) => {
|
||||
passport.authenticate("local", (err: Error, user: UserDocument, info: IVerifyOptions) => {
|
||||
if (err) { return next(err); }
|
||||
if (!user) {
|
||||
req.flash("errors", info.message);
|
||||
|
@ -57,7 +56,7 @@ export let postLogin = (req: Request, res: Response, next: NextFunction) => {
|
|||
* GET /logout
|
||||
* Log out.
|
||||
*/
|
||||
export let logout = (req: Request, res: Response) => {
|
||||
export const logout = (req: Request, res: Response) => {
|
||||
req.logout();
|
||||
res.redirect("/");
|
||||
};
|
||||
|
@ -66,7 +65,7 @@ export let logout = (req: Request, res: Response) => {
|
|||
* GET /signup
|
||||
* Signup page.
|
||||
*/
|
||||
export let getSignup = (req: Request, res: Response) => {
|
||||
export const getSignup = (req: Request, res: Response) => {
|
||||
if (req.user) {
|
||||
return res.redirect("/");
|
||||
}
|
||||
|
@ -79,7 +78,7 @@ export let getSignup = (req: Request, res: Response) => {
|
|||
* POST /signup
|
||||
* Create a new local account.
|
||||
*/
|
||||
export let postSignup = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postSignup = (req: Request, res: Response, next: NextFunction) => {
|
||||
req.assert("email", "Email is not valid").isEmail();
|
||||
req.assert("password", "Password must be at least 4 characters long").len({ min: 4 });
|
||||
req.assert("confirmPassword", "Passwords do not match").equals(req.body.password);
|
||||
|
@ -119,7 +118,7 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => {
|
|||
* GET /account
|
||||
* Profile page.
|
||||
*/
|
||||
export let getAccount = (req: Request, res: Response) => {
|
||||
export const getAccount = (req: Request, res: Response) => {
|
||||
res.render("account/profile", {
|
||||
title: "Account Management"
|
||||
});
|
||||
|
@ -129,7 +128,7 @@ export let getAccount = (req: Request, res: Response) => {
|
|||
* POST /account/profile
|
||||
* Update profile information.
|
||||
*/
|
||||
export let postUpdateProfile = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postUpdateProfile = (req: Request, res: Response, next: NextFunction) => {
|
||||
req.assert("email", "Please enter a valid email address.").isEmail();
|
||||
req.sanitize("email").normalizeEmail({ gmail_remove_dots: false });
|
||||
|
||||
|
@ -140,7 +139,7 @@ export let postUpdateProfile = (req: Request, res: Response, next: NextFunction)
|
|||
return res.redirect("/account");
|
||||
}
|
||||
|
||||
User.findById(req.user.id, (err, user: UserModel) => {
|
||||
User.findById(req.user.id, (err, user: UserDocument) => {
|
||||
if (err) { return next(err); }
|
||||
user.email = req.body.email || "";
|
||||
user.profile.name = req.body.name || "";
|
||||
|
@ -165,7 +164,7 @@ export let postUpdateProfile = (req: Request, res: Response, next: NextFunction)
|
|||
* POST /account/password
|
||||
* Update current password.
|
||||
*/
|
||||
export let postUpdatePassword = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postUpdatePassword = (req: Request, res: Response, next: NextFunction) => {
|
||||
req.assert("password", "Password must be at least 4 characters long").len({ min: 4 });
|
||||
req.assert("confirmPassword", "Passwords do not match").equals(req.body.password);
|
||||
|
||||
|
@ -176,7 +175,7 @@ export let postUpdatePassword = (req: Request, res: Response, next: NextFunction
|
|||
return res.redirect("/account");
|
||||
}
|
||||
|
||||
User.findById(req.user.id, (err, user: UserModel) => {
|
||||
User.findById(req.user.id, (err, user: UserDocument) => {
|
||||
if (err) { return next(err); }
|
||||
user.password = req.body.password;
|
||||
user.save((err: WriteError) => {
|
||||
|
@ -191,7 +190,7 @@ export let postUpdatePassword = (req: Request, res: Response, next: NextFunction
|
|||
* POST /account/delete
|
||||
* Delete user account.
|
||||
*/
|
||||
export let postDeleteAccount = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postDeleteAccount = (req: Request, res: Response, next: NextFunction) => {
|
||||
User.remove({ _id: req.user.id }, (err) => {
|
||||
if (err) { return next(err); }
|
||||
req.logout();
|
||||
|
@ -204,7 +203,7 @@ export let postDeleteAccount = (req: Request, res: Response, next: NextFunction)
|
|||
* GET /account/unlink/:provider
|
||||
* Unlink OAuth provider.
|
||||
*/
|
||||
export let getOauthUnlink = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const getOauthUnlink = (req: Request, res: Response, next: NextFunction) => {
|
||||
const provider = req.params.provider;
|
||||
User.findById(req.user.id, (err, user: any) => {
|
||||
if (err) { return next(err); }
|
||||
|
@ -222,7 +221,7 @@ export let getOauthUnlink = (req: Request, res: Response, next: NextFunction) =>
|
|||
* GET /reset/:token
|
||||
* Reset Password page.
|
||||
*/
|
||||
export let getReset = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const getReset = (req: Request, res: Response, next: NextFunction) => {
|
||||
if (req.isAuthenticated()) {
|
||||
return res.redirect("/");
|
||||
}
|
||||
|
@ -245,7 +244,7 @@ export let getReset = (req: Request, res: Response, next: NextFunction) => {
|
|||
* POST /reset/:token
|
||||
* Process the reset password request.
|
||||
*/
|
||||
export let postReset = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postReset = (req: Request, res: Response, next: NextFunction) => {
|
||||
req.assert("password", "Password must be at least 4 characters long.").len({ min: 4 });
|
||||
req.assert("confirm", "Passwords must match.").equals(req.body.password);
|
||||
|
||||
|
@ -278,7 +277,7 @@ export let postReset = (req: Request, res: Response, next: NextFunction) => {
|
|||
});
|
||||
});
|
||||
},
|
||||
function sendResetPasswordEmail(user: UserModel, done: Function) {
|
||||
function sendResetPasswordEmail(user: UserDocument, done: Function) {
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: "SendGrid",
|
||||
auth: {
|
||||
|
@ -307,7 +306,7 @@ export let postReset = (req: Request, res: Response, next: NextFunction) => {
|
|||
* GET /forgot
|
||||
* Forgot Password page.
|
||||
*/
|
||||
export let getForgot = (req: Request, res: Response) => {
|
||||
export const getForgot = (req: Request, res: Response) => {
|
||||
if (req.isAuthenticated()) {
|
||||
return res.redirect("/");
|
||||
}
|
||||
|
@ -320,7 +319,7 @@ export let getForgot = (req: Request, res: Response) => {
|
|||
* POST /forgot
|
||||
* Create a random token, then the send user an email with a reset link.
|
||||
*/
|
||||
export let postForgot = (req: Request, res: Response, next: NextFunction) => {
|
||||
export const postForgot = (req: Request, res: Response, next: NextFunction) => {
|
||||
req.assert("email", "Please enter a valid email address.").isEmail();
|
||||
req.sanitize("email").normalizeEmail({ gmail_remove_dots: false });
|
||||
|
||||
|
@ -352,7 +351,7 @@ export let postForgot = (req: Request, res: Response, next: NextFunction) => {
|
|||
});
|
||||
});
|
||||
},
|
||||
function sendForgotPasswordEmail(token: AuthToken, user: UserModel, done: Function) {
|
||||
function sendForgotPasswordEmail(token: AuthToken, user: UserDocument, done: Function) {
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: "SendGrid",
|
||||
auth: {
|
||||
|
|
|
@ -2,7 +2,7 @@ import bcrypt from "bcrypt-nodejs";
|
|||
import crypto from "crypto";
|
||||
import mongoose from "mongoose";
|
||||
|
||||
export type UserModel = mongoose.Document & {
|
||||
export type UserDocument = mongoose.Document & {
|
||||
email: string,
|
||||
password: string,
|
||||
passwordResetToken: string,
|
||||
|
@ -77,10 +77,7 @@ userSchema.methods.comparePassword = comparePassword;
|
|||
/**
|
||||
* Helper method for getting user's gravatar.
|
||||
*/
|
||||
userSchema.methods.gravatar = function (size: number) {
|
||||
if (!size) {
|
||||
size = 200;
|
||||
}
|
||||
userSchema.methods.gravatar = function (size: number = 200) {
|
||||
if (!this.email) {
|
||||
return `https://gravatar.com/avatar/?s=${size}&d=retro`;
|
||||
}
|
||||
|
@ -88,6 +85,4 @@ userSchema.methods.gravatar = function (size: number) {
|
|||
return `https://gravatar.com/avatar/${md5}?s=${size}&d=retro`;
|
||||
};
|
||||
|
||||
// export const User: UserType = mongoose.model<UserType>('User', userSchema);
|
||||
const User = mongoose.model("User", userSchema);
|
||||
export default User;
|
||||
export const User = mongoose.model<UserDocument>("User", userSchema);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import winston from "winston";
|
||||
import { Logger } from "winston";
|
||||
import { ENVIRONMENT } from "./secrets";
|
||||
|
||||
const logger = new (Logger)({
|
||||
transports: [
|
||||
|
|
|
@ -21,6 +21,10 @@ if (!SESSION_SECRET) {
|
|||
}
|
||||
|
||||
if (!MONGODB_URI) {
|
||||
logger.error("No mongo connection string. Set MONGODB_URI environment variable.");
|
||||
if (prod) {
|
||||
logger.error("No mongo connection string. Set MONGODB_URI environment variable.");
|
||||
} else {
|
||||
logger.error("No mongo connection string. Set MONGODB_URI_LOCAL environment variable.");
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче