Commit 26aef736 authored by dangdoan's avatar dangdoan

Merge branch 'develop' into 'test-meger'

# Conflicts:
#   .gitlab-ci.yml
#   package.json
parents bea55101 b755de72
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: maximegris # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: maximegris # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
{ {
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{
"args": [
"task"
],
"name": "Gulp task",
"program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"type": "node"
},
{ {
"name": "Debug Typescript", "name": "Debug Typescript",
"type": "node", "type": "node",
......
...@@ -69,6 +69,9 @@ curl -X POST -H 'Content-Type: application/json' -d '{"email":"foo@bar.com","pwd ...@@ -69,6 +69,9 @@ curl -X POST -H 'Content-Type: application/json' -d '{"email":"foo@bar.com","pwd
npm run build npm run build
``` ```
## Express Validator
https://github.com/validatorjs/validator.js#sanitizers
## Lint your code before you commit! ## Lint your code before you commit!
In a collaborative project, it's always a pain when you have to work on files not correctly formatted. In a collaborative project, it's always a pain when you have to work on files not correctly formatted.
......
...@@ -80,7 +80,7 @@ gulp.task(GENERATE_DOC, gulp.series(CLEAN_DOC, function () { ...@@ -80,7 +80,7 @@ gulp.task(GENERATE_DOC, gulp.series(CLEAN_DOC, function () {
return gulp.src(TS_SRC_GLOB) return gulp.src(TS_SRC_GLOB)
.pipe(typedoc({ .pipe(typedoc({
out: "docs", out: "docs",
target: "es5", target: "es6",
name: "Express + Sequelize", name: "Express + Sequelize",
module: "commonjs", module: "commonjs",
readme: "readme.md", readme: "readme.md",
......
{ {
"name": "typescript-express-sequelize", "name": "typescript-express-postgresql-sequelize",
"version": "2.1.0", "version": "1.0.0",
"description": "Sample project with Express + Sequelize + Typescript", "description": "A sample project with Express + Sequelize + Typescript + Postgresql",
"homepage": "https://github.com/maximegris/typescript-express-sequelize", "homepage": "",
"author": { "author": {
"name": "Maxime GRIS", "name": "Author",
"email": "maxime.gris@gmail.com" "email": "email@yourdomain.com"
}, },
"main": "build/src/server.js", "main": "build/src/server.js",
"keywords": [ "keywords": [
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
"scripts": { "scripts": {
"build": "gulp build", "build": "gulp build",
"doc": "gulp generate:doc", "doc": "gulp generate:doc",
"start": "cross-env NODE_ENV=development gulp watch", "start": "cross-env NODE_ENV=development gulp watch ",
"start:prod": "cross-env NODE_ENV=production gulp watch", "start:prod": "cross-env NODE_ENV=production gulp watch",
"run:test": "cross-env NODE_ENV=test gulp test", "run:test": "cross-env NODE_ENV=test gulp test",
"tslint": "gulp tslint", "tslint": "gulp tslint",
...@@ -37,10 +37,14 @@ ...@@ -37,10 +37,14 @@
"cross-env": "7.0.0", "cross-env": "7.0.0",
"express": "^4.17.1", "express": "^4.17.1",
"express-boom": "3.0.0", "express-boom": "3.0.0",
"express-validator": "^6.9.2",
"kafka-node": "^5.0.0",
"morgan": "1.9.1", "morgan": "1.9.1",
"pg": "^8.5.1", "pg": "^8.5.1",
"pg-hstore": "^2.3.3", "pg-hstore": "^2.3.3",
"sequelize": "^6.5.0", "sequelize": "^6.5.0",
"swagger-jsdoc": "^6.0.7",
"swagger-ui-express": "^4.1.4",
"uuid": "3.4.0", "uuid": "3.4.0",
"winston": "3.2.1" "winston": "3.2.1"
}, },
...@@ -62,7 +66,7 @@ ...@@ -62,7 +66,7 @@
"lint-staged": "10.0.7", "lint-staged": "10.0.7",
"remap-istanbul": "0.13.0", "remap-istanbul": "0.13.0",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"sequelize-cli": "5.5.1", "sequelize-cli": "^5.5.1",
"tslint": "6.0.0", "tslint": "6.0.0",
"typedoc": "0.16.10", "typedoc": "0.16.10",
"typescript": "3.8.2", "typescript": "3.8.2",
......
{
"development": {
"username": "postgres",
"password": "chinguyen",
"database": "node_sequelize",
"host": "127.0.0.1",
"port": 5432,
"dialect": "postgres"
}
}
\ No newline at end of file
import * as LanguagesDao from './languages' import * as LanguagesDao from './languages'
import * as AppUserDao from './appusers' import * as AppUserDao from './appusers'
import * as StudentDao from './students'
// For kafka only
// import * as ConsumerDao from '../kafka/consumerMessage'
// import * as ProducerDao from '../kafka/messageProducer'
export { LanguagesDao } export { LanguagesDao }
export { AppUserDao } export { AppUserDao }
export { StudentDao }
// For kafka only
// export { ConsumerDao }
// export { ProducerDao }
import * as uuid from 'uuid' import * as uuid from 'uuid'
import { AppUser } from './../sqlz/models/appuser' import { AppUsers } from './../sqlz/models/appuser'
import { Language } from '../sqlz/models/language' import { Language } from '../sqlz/models/language'
export function create(appUser: any): Promise<any> { export function createUserDao(appUsers: any): Promise<any> {
return AppUsers
return Language.findOne({ .create({
where: { name: 'fr' } id: uuid.v1(),
}) email: appUsers.email,
.then(language => { pwd: appUsers.pwd
return AppUser
.create({
id: uuid.v1(),
email: appUser.email,
pwd: appUser.pwd,
languageId: language.get('id')
})
}) })
} }
export function findAll(): Promise<any> { export function findAll(): Promise<any> {
return AppUser return AppUsers
.findAll({ include: [{ all: true }] }) .findAll({ include: [{ all: true }] })
} }
export function login(appUser: any): Promise<any> { export function login(appUser: any): Promise<any> {
return AppUser return AppUsers
.findOne({ .findOne({
where: { where: {
email: appUser.email, email: appUser.email,
pwd: appUser.pwd pwd: appUser.pwd
}, },
include: [Language] // include: [Language]
}) })
} }
import * as uuid from 'uuid'
import { Students } from './../sqlz/models/students'
import { where, Op } from 'sequelize/types'
import { Request, Response } from 'express'
export function create(students: any): Promise<any> {
return Students.create({
id: uuid.v1(),
code: students.code,
firstname: students.firstname,
lastname: students.lastname,
email: students.email,
sdt: students.sdt
})
}
export function findAll(): Promise<any> {
return Students.findAll()
}
export function findStudentPagination(page: any, pagesize: any): Promise<any> {
return Students.findAndCountAll({
offset: (page - 1) * pagesize,
limit: pagesize
//offset: 1,
//limit: 2
})
}
export function deleteUser(code: any): Promise<any> {
return Students.destroy({
where: { code }
})
}
export function updateUser(code: any, students: any): Promise<any> {
return Students.findOne({
where: { code }
}).then(function(student) {
if (student) {
student.update({
firstname: students.firstname,
lastname: students.lastname,
email: students.email,
sdt: students.sdt
})
}
})
}
import * as LanguageController from './languages/_index' import * as LanguageController from './languages/_index'
import * as AppUserController from './appusers/_index' import * as AppUserController from './appusers/_index'
import * as StudentsController from './students/_index'
// For kafka only
// import * as ConsumerController from './consumer/_index'
// import * as ProducerController from './producer/_index'
export { LanguageController, AppUserController } export { LanguageController, AppUserController, StudentsController }
import { Request, Response } from 'express' import { Request, Response } from 'express'
import { AppUserDao } from '../../dao/_index' import { AppUserDao } from '../../dao/_index'
import { body, validationResult } from 'express-validator'
export function create(req: Request, res: Response) {
const createUserValidationRules = [
req.checkBody('pwd', 'Password is required').notEmpty() body('pwd', 'Password is required').notEmpty(),
req.checkBody('email', 'Email is required').notEmpty() body('email', 'Email is required').notEmpty(),
req.checkBody('email', 'A valid email is required').isEmail() body('email', 'A valid email is required').isEmail()
]
req.getValidationResult()
.then(function(result) { const loginValidationRules = [
if (result.isEmpty()) { body('pwd', 'Password is required').notEmpty(),
return AppUserDao.create(req.body) body('email', 'Email is required').notEmpty(),
.then(appuser => res.status(201).send(appuser)) body('email', 'A valid email is required').isEmail()
.catch(error => res.boom.badRequest(error)) ]
} else {
res.boom.badRequest('Validation errors', result.mapped()) export function getValidationRules(method) {
} switch (method) {
}) case 'CreateUser': {
return createUserValidationRules
}
case 'Login': {
return loginValidationRules
}
}
}
export function createUser(req: Request, res: Response) {
let errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
return AppUserDao.createUserDao(req.body).then(user => res.json(user))
} }
export function login(req: Request, res: Response) { export function login(req: Request, res: Response) {
let errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
req.checkBody('pwd', 'Password is required').notEmpty() return AppUserDao.login(req.body).then(user => res.json(user))
req.checkBody('email', 'Email is required').notEmpty()
req.checkBody('email', 'A valid email is required').isEmail()
req.getValidationResult()
.then(function(result) {
if (result.isEmpty()) {
return AppUserDao.login(req.body)
} else {
res.boom.badRequest('Validation errors', result.mapped())
}
})
.then(appuser => res.status(200).send(appuser))
.catch(error => res.boom.badRequest(error))
} }
import * as StudentsGet from './students.get'
import * as StudentsPost from './students.post'
import * as StudentsDelete from './students.delete'
import * as StudentsPut from './students.put'
export { StudentsGet, StudentsPost, StudentsDelete, StudentsPut }
\ No newline at end of file
import { Request, Response } from 'express'
import { StudentDao } from '../../dao/_index'
export function deleteUser(req: Request, res: Response) {
return StudentDao.deleteUser(req.params.code).then(res.status(200).json({success: true, message: 'delete success'}))
}
import { Request, Response } from 'express'
import { StudentDao } from '../../dao/_index'
export function getAllUsers(req: Request, res: Response) {
return StudentDao
.findAll()
.then(students => res.status(200).send(students))
.catch(error => res.boom.badRequest(error))
}
export function getUserBasePagination(req: Request, res: Response) {
return StudentDao.findStudentPagination(req.query.page, req.query.pagesize)
.then(students => res.status(200).send(students.rows))
}
import { Request, Response } from 'express'
import { StudentDao } from '../../dao/_index'
export function Add(req: Request, res: Response) {
return StudentDao
.create(req.body)
.then(students => res.status(200).send(students))
.catch(error => res.boom.badRequest(error))
}
import { Request, Response } from 'express'
import { StudentDao } from '../../dao/_index'
export function updateUser(req: Request, res: Response) {
return StudentDao.updateUser(req.params.code, req.body).then(res.status(200).json({success: true, message: 'update successful'}))
}
\ No newline at end of file
File added
...@@ -2,6 +2,7 @@ import * as winston from 'winston' ...@@ -2,6 +2,7 @@ import * as winston from 'winston'
import { Express, Request, Response } from 'express' import { Express, Request, Response } from 'express'
import * as LanguagesRoutes from './languages' import * as LanguagesRoutes from './languages'
import * as AppUserRoutes from './appusers' import * as AppUserRoutes from './appusers'
import * as StudentsRoutes from './students'
export function initRoutes(app: Express) { export function initRoutes(app: Express) {
winston.log('info', '--> Initialisations des routes') winston.log('info', '--> Initialisations des routes')
...@@ -12,6 +13,7 @@ export function initRoutes(app: Express) { ...@@ -12,6 +13,7 @@ export function initRoutes(app: Express) {
LanguagesRoutes.routes(app) LanguagesRoutes.routes(app)
AppUserRoutes.routes(app) AppUserRoutes.routes(app)
StudentsRoutes.routes(app)
app.all('*', (req: Request, res: Response) => res.boom.notFound()) app.all('*', (req: Request, res: Response) => res.boom.notFound())
} }
...@@ -2,9 +2,16 @@ import { Express } from 'express' ...@@ -2,9 +2,16 @@ import { Express } from 'express'
import { AppUserController } from '../endpoints/_index' import { AppUserController } from '../endpoints/_index'
export function routes(app: Express) { export function routes(app: Express) {
/**
app.get('/api/appUsers', AppUserController.AppUserGet.list) * @swagger
app.post('/api/appUsers', AppUserController.AppUserPost.create) * /api/users:
app.post('/api/appUsers/login', AppUserController.AppUserPost.login) * get:
* description: Get all users
* responses:
* '200':
* description: A successful response
*/
app.get('/api/users', AppUserController.AppUserGet.list)
app.post('/api/user', AppUserController.AppUserPost.getValidationRules('CreateUser'), AppUserController.AppUserPost.createUser)
app.post('/api/user/login', AppUserController.AppUserPost.getValidationRules('Login'), AppUserController.AppUserPost.login)
} }
import { Express } from 'express'
import { StudentsController } from '../endpoints/_index'
export function routes(app: Express) {
app.get('/api/students/all', StudentsController.StudentsGet.getAllUsers)
app.get('/api/students/paging*', StudentsController.StudentsGet.getUserBasePagination )
app.post('/api/addStudent', StudentsController.StudentsPost.Add)
app.delete('/api/deleteStudent/:code', StudentsController.StudentsDelete.deleteUser)
app.put('/api/updateStudent/:code',StudentsController.StudentsPut.updateUser)
}
\ No newline at end of file
...@@ -6,6 +6,9 @@ import * as cors from 'cors' ...@@ -6,6 +6,9 @@ import * as cors from 'cors'
import { json, urlencoded } from 'body-parser' import { json, urlencoded } from 'body-parser'
import { Express } from 'express' import { Express } from 'express'
import * as routes from './routes/_index' import * as routes from './routes/_index'
import * as specs from './swagger'
import * as swaggerUi from 'swagger-ui-express'
const PORT: number = 3000 const PORT: number = 3000
...@@ -14,22 +17,23 @@ const PORT: number = 3000 ...@@ -14,22 +17,23 @@ const PORT: number = 3000
* Can be used for basic configurations, for instance starting up the server or registering middleware. * Can be used for basic configurations, for instance starting up the server or registering middleware.
*/ */
export class Server { export class Server {
private app: Express private app: Express
constructor() { constructor() {
this.app = express() this.app = express()
// Express middleware // Express middleware
this.app.use(cors({ this.app.use(cors({ optionsSuccessStatus: 200 }))
optionsSuccessStatus: 200 this.app.use(urlencoded({ extended: true }))
}))
this.app.use(urlencoded({
extended: true
}))
this.app.use(json()) this.app.use(json())
this.app.use(boom()) this.app.use(boom())
this.app.use(morgan('combined')) this.app.use(morgan('combined'))
if (process.env["EnvironmentName"] == "development") {
this.app.use('/swagger', swaggerUi.serve, swaggerUi.setup(specs.default));
}
this.app.listen(PORT, () => { this.app.listen(PORT, () => {
winston.log('info', '--> Server successfully started at port %d', PORT) winston.log('info', '--> Server successfully started at port %d', PORT)
}) })
......
{ {
"development": { "development": {
"username": "postgres", "username": "postgres",
"password": "chinguyen", "password": "meu@sds12@!#gh",
"database": "node_sequelize", "database": "chinguyen_nodejs-practice",
"host": "127.0.0.1", "host": "27.74.255.96",
"port": 5432, "port": 5430,
"dialect": "postgres" "dialect": "postgres"
} }
} }
\ No newline at end of file
'use strict';
module.exports = {
up: async(queryInterface, Sequelize) => {
await queryInterface.createTable('Students', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV1
},
code: {
type: Sequelize.STRING
},
firstname: {
type: Sequelize.STRING
},
lastname: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
sdt: {
type: Sequelize.STRING
},
createdAt: {
allowNull: true,
type: Sequelize.DATE
},
updatedAt: {
allowNull: true,
type: Sequelize.DATE
}
});
},
down: async(queryInterface, Sequelize) => {
await queryInterface.dropTable('Students');
}
};
\ No newline at end of file
...@@ -2,26 +2,23 @@ import { Model, STRING, UUID, Deferrable } from 'sequelize' ...@@ -2,26 +2,23 @@ import { Model, STRING, UUID, Deferrable } from 'sequelize'
import sequelize from './_index' import sequelize from './_index'
import { Language } from './language' import { Language } from './language'
export class AppUser extends Model { export class AppUsers extends Model {
} }
export class AppUserModel { export class AppUsersModel {
id: string id: string
name: string email: string
pwd: string pwd: string
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date
} }
AppUser.init( AppUsers.init(
{ {
email: STRING(50), email: STRING,
pwd: STRING(50) pwd: STRING
}, },
{ sequelize, modelName: 'AppUser' } { sequelize, modelName: 'AppUsers' },
) )
AppUser.belongsTo(Language, {
foreignKey: 'languageId'
})
import { Model, STRING, UUID } from 'sequelize' import { Model, STRING, UUID } from 'sequelize'
import sequelize from './_index' import sequelize from './_index'
import { AppUser } from './appuser' import { AppUsers } from './appuser'
export class Language extends Model { export class Language extends Model {
} }
......
import { Model, STRING, UUID, Deferrable, NUMBER, DATE, INTEGER, BIGINT } from 'sequelize'
import sequelize from './_index'
export class Students extends Model {
}
export class StudentsModel {
id: string
code: string
firstname: string
lastname: string
email: string
sdt: string
createdAt: Date
updatedAt: Date
}
Students.init({
code: STRING,
firstname: STRING,
lastname: STRING,
email: STRING,
sdt: STRING
}, {
sequelize,
modelName: 'Students',
})
\ No newline at end of file
import * as swaggerJsdoc from 'swagger-jsdoc'
const options = {
apis: ['**/*.ts'],
explorer: true,
swaggerDefinition: {
info: {
swagger: '2.0',
title: "Sample project APIs doc",
description: "Your project description here",
contact: {
name: "Author name"
},
version: '1.0.0'
}
}
};
const specs = swaggerJsdoc(options);
export default specs;
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
"module": "commonjs", "module": "commonjs",
"declaration": false, "declaration": false,
"noImplicitAny": false, "noImplicitAny": false,
"resolveJsonModule": true,
"skipLibCheck": true,
"removeComments": true, "removeComments": true,
"noLib": false, "noLib": false,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
......
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