separate client and server apps
This commit is contained in:
parent
e5f6840013
commit
cba40b6aff
@ -14,11 +14,12 @@ module.exports = {
|
|||||||
node: true,
|
node: true,
|
||||||
jest: true,
|
jest: true,
|
||||||
},
|
},
|
||||||
ignorePatterns: ['.eslintrc.js'],
|
ignorePatterns: ['.eslintrc.js', '.babelrc'],
|
||||||
rules: {
|
rules: {
|
||||||
'@typescript-eslint/interface-name-prefix': 'off',
|
'@typescript-eslint/interface-name-prefix': 'off',
|
||||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-empty-function': 'off'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
# compiled output
|
# compiled output
|
||||||
/dist
|
dist
|
||||||
/node_modules
|
static
|
||||||
|
node_modules
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
|
73
README.md
73
README.md
@ -1,12 +1,49 @@
|
|||||||
# Nest Starter App
|
# Nest Starter App
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
A starter app with LTI1p0 enabled for NestJS
|
A starter app with Postgres, NestJS, and React
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
### asdf-vm
|
||||||
|
Tool versions are managed using `asdf-vm`. You will need to have `asdf-vm` installed first.
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
### Tool versions
|
||||||
|
Install the tool versions by running
|
||||||
|
```bash
|
||||||
|
$ asdf install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install yarn
|
||||||
|
We will use `yarn` instead of `npm` for package managment
|
||||||
|
```bash
|
||||||
|
$ npm install -g yarn
|
||||||
|
```
|
||||||
|
|
||||||
|
### .env
|
||||||
Create a file in the root called `.env` and copy the contents of `.env.example`
|
Create a file in the root called `.env` and copy the contents of `.env.example`
|
||||||
|
|
||||||
## SSL
|
### Dependencies
|
||||||
|
To install the dependencies run
|
||||||
|
```bash
|
||||||
|
$ yarn # this is same thing as `yarn install`
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database
|
||||||
|
Create the database
|
||||||
|
```bash
|
||||||
|
$ pc_ctl start # this starts postgres
|
||||||
|
$ createdb neststarterappdevelopement # creates a postgres database
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the migrations
|
||||||
|
```bash
|
||||||
|
yarn db:migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
Migrations need to be run again everytime a new migration is created
|
||||||
|
|
||||||
|
### SSL
|
||||||
Create a ssl key and certificate an place them in the root directory
|
Create a ssl key and certificate an place them in the root directory
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@ -14,48 +51,28 @@ $ openssl req -x509 -newkey rsa:4096 -keyout private-key.pem -out public-cert.pe
|
|||||||
```
|
```
|
||||||
Where this key will only be used for development you can leave all of the information blank.
|
Where this key will only be used for development you can leave all of the information blank.
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
## Running the app
|
## Running the app
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# development
|
# development
|
||||||
$ npm run start
|
$ yarn start
|
||||||
|
|
||||||
# watch mode
|
# watch mode
|
||||||
$ npm run start:dev
|
$ yarn start:dev
|
||||||
|
|
||||||
# production mode
|
# production mode
|
||||||
$ npm run start:prod
|
$ yarn start:prod
|
||||||
```
|
```
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# unit tests
|
# unit tests
|
||||||
$ npm run test
|
$ yarn test
|
||||||
|
|
||||||
# e2e tests
|
# e2e tests
|
||||||
$ npm run test:e2e
|
$ yarn test:e2e
|
||||||
|
|
||||||
# test coverage
|
# test coverage
|
||||||
$ npm run test:cov
|
$ yarn test:cov
|
||||||
```
|
```
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
|
||||||
|
|
||||||
## Stay in touch
|
|
||||||
|
|
||||||
- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
|
|
||||||
- Website - [https://nestjs.com](https://nestjs.com/)
|
|
||||||
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Nest is [MIT licensed](LICENSE).
|
|
||||||
|
39
client/app.jsx
Normal file
39
client/app.jsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { setConstantValue } from 'typescript';
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
const [email, setEmail] = useState('');
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
|
||||||
|
const submit = () => {
|
||||||
|
fetch('/sign_in', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ email, password }),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
value={email}
|
||||||
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type="button" onClick={submit}>Login</button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
5
client/index.js
Normal file
5
client/index.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import App from './app';
|
||||||
|
|
||||||
|
const app = document.getElementById('app');
|
||||||
|
ReactDOM.render(<App />, app);
|
13
client/package.json
Normal file
13
client/package.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "nestclientstarterapp-client",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"scripts": {},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^17.0.2",
|
||||||
|
"react-dom": "^17.0.2"
|
||||||
|
}
|
||||||
|
}
|
45
client/yarn.lock
Normal file
45
client/yarn.lock
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"js-tokens@^3.0.0 || ^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||||
|
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||||
|
|
||||||
|
loose-envify@^1.1.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||||
|
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||||
|
dependencies:
|
||||||
|
js-tokens "^3.0.0 || ^4.0.0"
|
||||||
|
|
||||||
|
object-assign@^4.1.1:
|
||||||
|
version "4.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
|
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||||
|
|
||||||
|
react-dom@^17.0.2:
|
||||||
|
version "17.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
|
||||||
|
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
object-assign "^4.1.1"
|
||||||
|
scheduler "^0.20.2"
|
||||||
|
|
||||||
|
react@^17.0.2:
|
||||||
|
version "17.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
|
||||||
|
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
object-assign "^4.1.1"
|
||||||
|
|
||||||
|
scheduler@^0.20.2:
|
||||||
|
version "0.20.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
|
||||||
|
integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
object-assign "^4.1.1"
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"collection": "@nestjs/schematics",
|
"collection": "@nestjs/schematics",
|
||||||
"sourceRoot": "src"
|
"sourceRoot": "server"
|
||||||
}
|
}
|
||||||
|
35
package.json
35
package.json
@ -6,28 +6,40 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start:db": "pg_ctl status || pg_ctl start",
|
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config src/database/cli_config.ts",
|
||||||
"stop:db": "pg_ctl status && pg_ctl stop",
|
"db:start": "pg_ctl status || pg_ctl start",
|
||||||
|
"db:stop": "pg_ctl status && pg_ctl stop",
|
||||||
|
"db:migration:create": "cd server/migrations && typeorm migration:create -n ",
|
||||||
|
"db:migrate": "yarn db:start && yarn typeorm migration:run",
|
||||||
|
"db:migrate:undo": "yarn db:start && yarn typeorm migration:revert",
|
||||||
"prebuild": "rimraf dist",
|
"prebuild": "rimraf dist",
|
||||||
"build": "nest build",
|
"build": "nest build && yarn client:build",
|
||||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
"format": "prettier --write \"server/**/*.ts\" \"test/**/*.ts\"",
|
||||||
"start": "nest start",
|
"start": "nest start",
|
||||||
"start:dev": "yarn start:db && nest start --watch",
|
"start:dev": "yarn db:start && nest start --watch",
|
||||||
"start:debug": "yarn start:db && nest start --debug --watch",
|
"start:debug": "yarn db:start && nest start --debug --watch",
|
||||||
"start:prod": "node dist/main",
|
"start:prod": "node dist/main",
|
||||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
"lint": "eslint \"{server,apps,libs,test}/**/*.ts\" --fix",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
"test:cov": "jest --coverage",
|
"test:cov": "jest --coverage",
|
||||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||||
|
"client:build": "parcel build ./client/index.js --dist-dir static",
|
||||||
|
"client:watch": "parcel watch ./client/index.js --dist-dir static"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs/common": "^8.0.0",
|
"@nestjs/common": "^8.0.0",
|
||||||
"@nestjs/core": "^8.0.0",
|
"@nestjs/core": "^8.0.0",
|
||||||
"@nestjs/platform-express": "^8.0.0",
|
"@nestjs/platform-express": "^8.0.0",
|
||||||
|
"@nestjs/serve-static": "^2.2.2",
|
||||||
"@nestjs/typeorm": "^8.0.2",
|
"@nestjs/typeorm": "^8.0.2",
|
||||||
|
"bcrypt": "^5.0.1",
|
||||||
|
"cookie-parser": "^1.4.6",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
|
"hbs": "^4.1.2",
|
||||||
|
"jsonwebtoken": "^8.5.1",
|
||||||
|
"morgan": "^1.10.0",
|
||||||
"pg": "^8.7.1",
|
"pg": "^8.7.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
@ -38,6 +50,7 @@
|
|||||||
"@nestjs/cli": "^8.0.0",
|
"@nestjs/cli": "^8.0.0",
|
||||||
"@nestjs/schematics": "^8.0.0",
|
"@nestjs/schematics": "^8.0.0",
|
||||||
"@nestjs/testing": "^8.0.0",
|
"@nestjs/testing": "^8.0.0",
|
||||||
|
"@types/cookie-parser": "^1.4.2",
|
||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
"@types/jest": "^27.0.1",
|
"@types/jest": "^27.0.1",
|
||||||
"@types/node": "^16.0.0",
|
"@types/node": "^16.0.0",
|
||||||
@ -48,10 +61,10 @@
|
|||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-plugin-prettier": "^3.4.0",
|
"eslint-plugin-prettier": "^3.4.0",
|
||||||
"jest": "^27.0.6",
|
"jest": "^27.0.6",
|
||||||
"prettier": "^2.3.2",
|
"parcel": "^2.0.1",
|
||||||
|
"prettier": "^2.4.1",
|
||||||
"supertest": "^6.1.3",
|
"supertest": "^6.1.3",
|
||||||
"ts-jest": "^27.0.3",
|
"ts-jest": "^27.0.3",
|
||||||
"ts-loader": "^9.2.3",
|
|
||||||
"ts-node": "^10.0.0",
|
"ts-node": "^10.0.0",
|
||||||
"tsconfig-paths": "^3.10.1",
|
"tsconfig-paths": "^3.10.1",
|
||||||
"typescript": "^4.3.5"
|
"typescript": "^4.3.5"
|
||||||
@ -62,7 +75,7 @@
|
|||||||
"json",
|
"json",
|
||||||
"ts"
|
"ts"
|
||||||
],
|
],
|
||||||
"rootDir": "src",
|
"rootDir": "server",
|
||||||
"testRegex": ".*\\.spec\\.ts$",
|
"testRegex": ".*\\.spec\\.ts$",
|
||||||
"transform": {
|
"transform": {
|
||||||
"^.+\\.(t|j)s$": "ts-jest"
|
"^.+\\.(t|j)s$": "ts-jest"
|
||||||
|
8
server/app.controller.ts
Normal file
8
server/app.controller.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Controller, Get, Render } from '@nestjs/common';
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
export class AppController {
|
||||||
|
@Get()
|
||||||
|
@Render('index')
|
||||||
|
index() {}
|
||||||
|
}
|
13
server/app.module.ts
Normal file
13
server/app.module.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { AppController } from './app.controller';
|
||||||
|
import { AppService } from './app.service';
|
||||||
|
import { config } from './database/config';
|
||||||
|
import { UsersModule } from './modules/users.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [TypeOrmModule.forRoot(config), UsersModule],
|
||||||
|
controllers: [AppController],
|
||||||
|
providers: [AppService],
|
||||||
|
})
|
||||||
|
export class AppModule {}
|
27
server/controllers/sessions.controller.ts
Normal file
27
server/controllers/sessions.controller.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { Body, Controller, Post, Res } from '@nestjs/common';
|
||||||
|
import { UsersService } from 'server/providers/services/users.service';
|
||||||
|
import { SignInDto } from '../dto/sign_in.dto';
|
||||||
|
import { Response } from 'express';
|
||||||
|
// this is kind of a misnomer because we are doing token based auth
|
||||||
|
// instead of session based auth
|
||||||
|
@Controller()
|
||||||
|
export class SessionsController {
|
||||||
|
constructor(private usersService: UsersService) {}
|
||||||
|
|
||||||
|
@Post('/sign_in')
|
||||||
|
async signIn(@Body() body: SignInDto, @Res() res: Response) {
|
||||||
|
console.log("DO I GET RAN?")
|
||||||
|
const verified = await this.usersService.verify(
|
||||||
|
body.username,
|
||||||
|
body.password,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!verified) {
|
||||||
|
res.status(400);
|
||||||
|
console.log("here too??")
|
||||||
|
res.json({ message: 'Invalid email or password' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.json({ success: true });
|
||||||
|
}
|
||||||
|
}
|
22
server/database/cli_config.ts
Normal file
22
server/database/cli_config.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import '../env';
|
||||||
|
|
||||||
|
export = process.env.NODE_ENV === 'development'
|
||||||
|
? {
|
||||||
|
type: 'postgres',
|
||||||
|
host: 'localhost',
|
||||||
|
port: 5432,
|
||||||
|
database: process.env.DATABASE_URL,
|
||||||
|
autoLoadEntities: true,
|
||||||
|
migrations: ['src/database/migrations/*.ts'],
|
||||||
|
cli: {
|
||||||
|
migrationsDir: 'src/database/migrations',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
url: process.env.DATABASE_URL,
|
||||||
|
ssl: { rejectUnauthorized: true },
|
||||||
|
migrations: ['src/database/migrations/*.ts'],
|
||||||
|
cli: {
|
||||||
|
migrationsDir: 'src/database/migrations',
|
||||||
|
},
|
||||||
|
};
|
16
server/database/config.ts
Normal file
16
server/database/config.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||||
|
import '../env';
|
||||||
|
|
||||||
|
export const config: TypeOrmModuleOptions =
|
||||||
|
process.env.NODE_ENV === 'development'
|
||||||
|
? {
|
||||||
|
type: 'postgres',
|
||||||
|
host: 'localhost',
|
||||||
|
port: 5432,
|
||||||
|
database: process.env.DATABASE_URL,
|
||||||
|
autoLoadEntities: true,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
url: process.env.DATABASE_URL,
|
||||||
|
ssl: { rejectUnauthorized: true },
|
||||||
|
};
|
37
server/database/migrations/1637028716848-AddUser.ts
Normal file
37
server/database/migrations/1637028716848-AddUser.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { MigrationInterface, QueryRunner, Table } from 'typeorm';
|
||||||
|
|
||||||
|
export class AddUser1637028716848 implements MigrationInterface {
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.createTable(
|
||||||
|
new Table({
|
||||||
|
name: 'user',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
type: 'int',
|
||||||
|
isPrimary: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
type: 'text',
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'password_hash',
|
||||||
|
type: 'text',
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'email',
|
||||||
|
type: 'text',
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.dropTable('user');
|
||||||
|
}
|
||||||
|
}
|
4
server/dto/sign_in.dto.ts
Normal file
4
server/dto/sign_in.dto.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export class SignInDto {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
}
|
16
server/entities/user.entity.ts
Normal file
16
server/entities/user.entity.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class User {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
password_hash: string;
|
||||||
|
}
|
2
server/env.ts
Normal file
2
server/env.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import { config } from 'dotenv';
|
||||||
|
config();
|
26
server/main.ts
Normal file
26
server/main.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import './env';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import { NestFactory } from '@nestjs/core';
|
||||||
|
import { join } from 'path';
|
||||||
|
import * as morgan from 'morgan';
|
||||||
|
import { AppModule } from './app.module';
|
||||||
|
import { NestExpressApplication } from '@nestjs/platform-express';
|
||||||
|
|
||||||
|
async function bootstrap() {
|
||||||
|
let httpsOptions;
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
httpsOptions = {
|
||||||
|
key: fs.readFileSync('./private-key.pem'),
|
||||||
|
cert: fs.readFileSync('./public-cert.pem'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
|
||||||
|
httpsOptions,
|
||||||
|
});
|
||||||
|
app.use(morgan('tiny'));
|
||||||
|
app.useStaticAssets(join(__dirname, '..', 'static'));
|
||||||
|
app.setBaseViewsDir(join(__dirname, '../', 'views'));
|
||||||
|
app.setViewEngine('hbs');
|
||||||
|
await app.listen(process.env.PORT);
|
||||||
|
}
|
||||||
|
bootstrap();
|
11
server/modules/users.module.ts
Normal file
11
server/modules/users.module.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { User } from 'server/entities/user.entity';
|
||||||
|
import { SessionsController } from '../controllers/sessions.controller';
|
||||||
|
import { UsersService } from '../providers/services/users.service';
|
||||||
|
@Module({
|
||||||
|
imports: [TypeOrmModule.forFeature([User])],
|
||||||
|
controllers: [SessionsController],
|
||||||
|
providers: [UsersService],
|
||||||
|
})
|
||||||
|
export class UsersModule {}
|
27
server/providers/services/users.service.ts
Normal file
27
server/providers/services/users.service.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import bcrypt from 'bcrypt';
|
||||||
|
import { User } from '../../entities/user.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UsersService {
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(User)
|
||||||
|
private usersRespository: Repository<User>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
findBy(options: Record<string, any>) {
|
||||||
|
return this.usersRespository.findOne(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
find(id: number) {
|
||||||
|
return this.usersRespository.findOne(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async verify(email: string, password: string) {
|
||||||
|
const user = await this.usersRespository.findOne({ email });
|
||||||
|
if (!user) return false;
|
||||||
|
return bcrypt.compare(password, user.password_hash);
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +0,0 @@
|
|||||||
import { Controller, Get } from '@nestjs/common';
|
|
||||||
import { AppService } from './app.service';
|
|
||||||
|
|
||||||
@Controller()
|
|
||||||
export class AppController {
|
|
||||||
constructor(private readonly appService: AppService) {}
|
|
||||||
|
|
||||||
@Get()
|
|
||||||
getHello(): string {
|
|
||||||
return this.appService.getHello();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
import { Module } from '@nestjs/common';
|
|
||||||
import { AppController } from './app.controller';
|
|
||||||
import { AppService } from './app.service';
|
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
imports: [
|
|
||||||
TypeOrmModule.forRoot(process.env.NODE_ENV === 'development' ? {
|
|
||||||
type: 'postgres',
|
|
||||||
host: 'localhost',
|
|
||||||
port: 5432,
|
|
||||||
database: process.env.DATABASE_URL,
|
|
||||||
autoLoadEntities: true,
|
|
||||||
} : {
|
|
||||||
url: process.env.DATABASE_URL,
|
|
||||||
ssl: { rejectUnauthorized: true }
|
|
||||||
})
|
|
||||||
],
|
|
||||||
controllers: [AppController],
|
|
||||||
providers: [AppService],
|
|
||||||
})
|
|
||||||
export class AppModule {}
|
|
21
src/main.ts
21
src/main.ts
@ -1,21 +0,0 @@
|
|||||||
import { config } from 'dotenv';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import { NestFactory } from '@nestjs/core';
|
|
||||||
import { AppModule } from './app.module';
|
|
||||||
|
|
||||||
config();
|
|
||||||
|
|
||||||
async function bootstrap() {
|
|
||||||
let httpsOptions;
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
|
||||||
httpsOptions = {
|
|
||||||
key: fs.readFileSync('./private-key.pem'),
|
|
||||||
cert: fs.readFileSync('./public-cert.pem'),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const app = await NestFactory.create(AppModule, {
|
|
||||||
httpsOptions
|
|
||||||
});
|
|
||||||
await app.listen(process.env.PORT);
|
|
||||||
}
|
|
||||||
bootstrap();
|
|
9
views/index.hbs
Normal file
9
views/index.hbs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app" />
|
||||||
|
<script src="index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user