#84 added server set up

parent fbf6bc53
export const FRONTEND_URL = 'localhost:3000'
\ No newline at end of file
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
"@types/express": "^4.17.14", "@types/express": "^4.17.14",
"@types/nodemailer": "^6.4.6",
"bcrypt": "^5.1.0", "bcrypt": "^5.1.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.13.2", "class-validator": "^0.13.2",
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
"mongoose": "^6.7.0", "mongoose": "^6.7.0",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"nanoid": "^3.3.4", "nanoid": "^3.3.4",
"nodemailer": "^6.8.0",
"path": "^0.12.7", "path": "^0.12.7",
"pg": "^8.8.0", "pg": "^8.8.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
...@@ -1712,6 +1714,14 @@ ...@@ -1712,6 +1714,14 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.8.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.8.tgz",
"integrity": "sha512-uGwPWlE0Hj972KkHtCDVwZ8O39GmyjfMane1Z3GUBGGnkZ2USDq7SxLpVIiIHpweY9DS0QTDH0Nw7RNBsAAZ5A==" "integrity": "sha512-uGwPWlE0Hj972KkHtCDVwZ8O39GmyjfMane1Z3GUBGGnkZ2USDq7SxLpVIiIHpweY9DS0QTDH0Nw7RNBsAAZ5A=="
}, },
"node_modules/@types/nodemailer": {
"version": "6.4.6",
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.6.tgz",
"integrity": "sha512-pD6fL5GQtUKvD2WnPmg5bC2e8kWCAPDwMPmHe/ohQbW+Dy0EcHgZ2oCSuPlWNqk74LS5BVMig1SymQbFMPPK3w==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/qs": { "node_modules/@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
...@@ -4488,6 +4498,14 @@ ...@@ -4488,6 +4498,14 @@
"webidl-conversions": "^3.0.0" "webidl-conversions": "^3.0.0"
} }
}, },
"node_modules/nodemailer": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.8.0.tgz",
"integrity": "sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/nodemon": { "node_modules/nodemon": {
"version": "2.0.20", "version": "2.0.20",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
...@@ -7663,6 +7681,14 @@ ...@@ -7663,6 +7681,14 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.8.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.8.tgz",
"integrity": "sha512-uGwPWlE0Hj972KkHtCDVwZ8O39GmyjfMane1Z3GUBGGnkZ2USDq7SxLpVIiIHpweY9DS0QTDH0Nw7RNBsAAZ5A==" "integrity": "sha512-uGwPWlE0Hj972KkHtCDVwZ8O39GmyjfMane1Z3GUBGGnkZ2USDq7SxLpVIiIHpweY9DS0QTDH0Nw7RNBsAAZ5A=="
}, },
"@types/nodemailer": {
"version": "6.4.6",
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.6.tgz",
"integrity": "sha512-pD6fL5GQtUKvD2WnPmg5bC2e8kWCAPDwMPmHe/ohQbW+Dy0EcHgZ2oCSuPlWNqk74LS5BVMig1SymQbFMPPK3w==",
"requires": {
"@types/node": "*"
}
},
"@types/qs": { "@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
...@@ -9721,6 +9747,11 @@ ...@@ -9721,6 +9747,11 @@
} }
} }
}, },
"nodemailer": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.8.0.tgz",
"integrity": "sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ=="
},
"nodemon": { "nodemon": {
"version": "2.0.20", "version": "2.0.20",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
"@types/express": "^4.17.14", "@types/express": "^4.17.14",
"@types/nodemailer": "^6.4.6",
"bcrypt": "^5.1.0", "bcrypt": "^5.1.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.13.2", "class-validator": "^0.13.2",
...@@ -37,6 +38,7 @@ ...@@ -37,6 +38,7 @@
"mongoose": "^6.7.0", "mongoose": "^6.7.0",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"nanoid": "^3.3.4", "nanoid": "^3.3.4",
"nodemailer": "^6.8.0",
"path": "^0.12.7", "path": "^0.12.7",
"pg": "^8.8.0", "pg": "^8.8.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
......
...@@ -2,6 +2,8 @@ import express, { NextFunction, Request, Response, Router } from "express"; ...@@ -2,6 +2,8 @@ import express, { NextFunction, Request, Response, Router } from "express";
import { myDataSource } from "./app-data-source"; import { myDataSource } from "./app-data-source";
import { Task } from "./models/Task"; import { Task } from "./models/Task";
import { User } from "./models/User"; import { User } from "./models/User";
import nodemailer from 'nodemailer';
const dataSource = myDataSource; const dataSource = myDataSource;
...@@ -75,4 +77,17 @@ export const taskFinderById = async (taskId:string):Promise<null | Task>=>{ ...@@ -75,4 +77,17 @@ export const taskFinderById = async (taskId:string):Promise<null | Task>=>{
} }
}) })
return task return task
} }
\ No newline at end of file
export let transporter = nodemailer.createTransport({
host: "smtp.yandex.ru",
port: 465,
secure: true, // true for 465, false for other ports
auth: {
user: "planner45", // generated ethereal user
pass: "newPlannerProject123" // generated ethereal password
}
})
\ No newline at end of file
...@@ -9,10 +9,10 @@ import { ...@@ -9,10 +9,10 @@ import {
import { User } from './User'; import { User } from './User';
interface IPasswordRecovery{ interface IPasswordRecovery{
user: User; createdAt:Date;
token: string; token: string;
user: User;
enabled:boolean; enabled:boolean;
createdAt:Date;
} }
@Entity({name: 'PasswordRecovery'}) @Entity({name: 'PasswordRecovery'})
...@@ -23,7 +23,7 @@ import { User } from './User'; ...@@ -23,7 +23,7 @@ import { User } from './User';
@CreateDateColumn({ name: 'created_at', type: Date, default: new Date() }) @CreateDateColumn({ name: 'created_at', type: Date, default: new Date() })
createdAt!: Date; createdAt!: Date;
@Column({ name: 'token', type:'string', nullable:false}) @Column({ name: 'token', type:String, nullable:false})
token!: string; token!: string;
@OneToOne(()=>User, (user:{passwordRecovery:PasswordRecovery})=>user.passwordRecovery) @OneToOne(()=>User, (user:{passwordRecovery:PasswordRecovery})=>user.passwordRecovery)
......
...@@ -38,7 +38,6 @@ interface IUser { ...@@ -38,7 +38,6 @@ interface IUser {
} }
@Entity({ name: 'User' }) @Entity({ name: 'User' })
export class User extends BaseEntity implements IUser { export class User extends BaseEntity implements IUser {
@PrimaryGeneratedColumn("uuid") @PrimaryGeneratedColumn("uuid")
......
import express,{Router, Request, Response} from 'express';
import {User} from '../models/User';
import {myDataSource} from '../app-data-source';
import { nanoid } from 'nanoid';
import { PasswordRecovery } from '../models/PasswordRecovery';
import { transporter } from '../helpers';
const router:Router = express.Router();
const dataSource = myDataSource;
/**Make requiest to init recovery process */
router.post ('/', async (req:Request, res:Response):Promise<void |Response>=>{
const {email} = req.body
const user = await dataSource
.getRepository(User)
.findOne({
where:{
email:email
}
})
if (!user) return res.status(404).send({message:'user not found'})
const token = nanoid();
const url = `${process.env.FRONTEND_URL}/reset-password/${token}`;
try{
const passwordRecovery = await new PasswordRecovery()
passwordRecovery.user= user
passwordRecovery.token=token
passwordRecovery.save()
await transporter.sendMail({
from:"planner45@yandex.com",
to: `${email}`,
subject:"Запрос на восстановление пароля",
text:`Вы отправили запрос на восстановление пароля,
перейдите по ссылке плз:{url}`,
html:`Вы отправили запрос на восстановление пароля,
перейдите по ссылке плз: <br><a> href="${url} ">${url}</a>`});
return res.send({message:'Email succeffuly send'})
} catch (e){
console.log(e)
res.status(502).send({message:'mail got stuck'})
}
})
/**validate token t*/
router.get("/validate", async(req: Request, res: Response):Promise<Response>=>{
const token = req.query.token;
// if (!token) return res.send({message:'token is not valid'})
// const passwordRecovery = await dataSource
// .getRepository(PasswordRecovery)
// .findOne({
// where:{
// token: token
// }
// })
// if (!passwordRecovery) return res.send({message:'link is not valid'})
return res.send(token);
})
export default router;
\ No newline at end of file
...@@ -5,6 +5,7 @@ import tasks from './routers/tasks'; ...@@ -5,6 +5,7 @@ import tasks from './routers/tasks';
import projects from './routers/projects'; import projects from './routers/projects';
import {myDataSource} from './app-data-source'; import {myDataSource} from './app-data-source';
import copyTasks from './routers/copyTasks'; import copyTasks from './routers/copyTasks';
import passwordRev
myDataSource myDataSource
...@@ -25,6 +26,7 @@ app.use('/users',users) ...@@ -25,6 +26,7 @@ app.use('/users',users)
app.use('/tasks',tasks) app.use('/tasks',tasks)
app.use('/copy-tasks',copyTasks) app.use('/copy-tasks',copyTasks)
app.use('/projects',projects) app.use('/projects',projects)
app.use('/password-recovery',passwordRecovery)
const run = async() => { const run = async() => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment