Skip to content
Snippets Groups Projects
Commit d77fd106 authored by Sébastien DA ROCHA's avatar Sébastien DA ROCHA
Browse files

Merge branch 'feat/init-refact' into 'development'

Feat/init refact

See merge request !1
parents 55cc70b3 46cd8ab9
Branches
Tags
2 merge requests!2Version 1.0.0,!1Feat/init refact
Pipeline #12705 failed
node_modules
npm-debug.log
\ No newline at end of file
*.csv
*.dat
*.iml
*.log
*.out
*.pid
*.seed
*.sublime-*
*.swo
*.swp
*.tgz
*.xml
.DS_Store
.idea
.project
.strong-pm
coverage
node_modules
npm-debug.log
.vscode
# Don't commit *.env except the template
*.env
!template.env
stages:
- sonar-analysis
- build
variables:
SONAR_URL: https://sonarqube.forge.grandlyon.com
sonarqube:
stage: sonar-analysis
tags:
- build
only:
- master
before_script:
- export PATH=$PATH:/usr/local/bin/sonar-scanner-3.2.0.1227-linux/bin/
- export NODE_PATH=$NODE_PATH:`npm root -g`
script:
- >
sonar-scanner
-Dsonar.projectName=${SONAR_PROJECT_KEY}
-Dsonar.projectVersion=1.0
-Dsonar.sourceEncoding=UTF-8
-Dsonar.projectBaseDir=.
-Dsonar.host.url=${SONAR_URL}
-Dsonar.projectKey=${SONAR_PROJECT_KEY}
-Dsonar.login=${SONAR_TOKEN}
build_development:
stage: build
tags:
- build
only:
- development
script:
- export TAG=dev
- export POSTGRES_PORT=5436
- export CREDITS_SERVICE_BIND_PORT=3005
- docker-compose build
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker-compose push
- 'curl -X POST -F token=$CI_JOB_TOKEN -F ref=master -F variables[TAG]=${TAG} https://forge.grandlyon.com/api/v4/projects/566/trigger/pipeline'
build_release:
stage: build
tags:
- build
only:
- tags
script:
- export TAG=$(echo $CI_COMMIT_TAG | sed 's/v//g')
- export POSTGRES_PORT=5436
- export CREDITS_SERVICE_BIND_PORT=3005
- docker-compose build
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker-compose push
{
"singleQuote": true,
"trailingComma": "all"
}
\ No newline at end of file
FROM node:14.15.1-slim
# Create app directory
WORKDIR /app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
RUN npm install
# If you are building your code for production
#RUN npm install --only=production
# Bundle app source
COPY . .
CMD ["sh","-c", "export MIGRATING=1 && npm run typeorm:migrate-ci && export MIGRATING=0 && npm run start:prod"]
EXPOSE 3000
LICENSE 0 → 100644
This diff is collapsed.
# postgres-services
# Credits service
## Installation
```bash
# install node modules
$ npm install
```
## Environment variables
In order to run the code, some environment variables are needed. They are specified in the `template.env` file at the root of the project.
For a local deployment:
1. `cp template.env .env`
2. Edit .env according to the chosen configuration
The values will be read from the file by default, but you can override any of those by exporting manually the variable before launching the service.
## Running the app without docker
You will need to provide a healthy connection to a database in order for the service to start.
```bash
# development
$ npm run start
# watch mode
$ npm run start:dev
# production mode
$ npm run start:prod
```
## Running the app with docker
```bash
# build
$ docker-compose build
# deploy
$ docker-compose up [-d]
# build and deploy
$ docker-compose up --build [-d]
```
## Migrations
Migrations are done automaticaly the docker image on startup. You can run it manualy:
MIGRATING=1 npm run migrate:run
*ATTENTION* when migrating, tables belong to postgres, not to "user", you need to grant "user" the access to the tables.
docker-compose exec database-postgres psql --user postgres --password services
# Give the "POSTGRES_ADMIN_PASSWORD" password
GRANT ALL ON ALL TABLES IN SCHEMA public TO "user";
Replace "user" by the database user given in .env file.
## Test
Be carefull, end to end tests drop all data from you tables :
```bash
# create a venv
python3 -m venv venv
. bin/activate
# Install dependencies
pip install -r tests/requirements.txt
# Run end to end tests
pip
```
#FIXME: running tests destroys migration table, you can't apply migrations after this
## Setup
Start the DATABASE, and use psql to setup database user "user" (or whatever name you gave it) rights :
psql --user postgres services
# giv postgres password
GRANT ALL ON DATABASE services TO "user";
GRANT ALL ON ALL TABLES IN SCHEMA public TO "user";
GRANT ALL ON ALL SEQUENCES IN SCHEMA "public" TO "user";
# Use postgres/example user/password credentials
version: '3'
services:
postgres-services:
build: .
image: registry.forge.grandlyon.com/web-et-numerique/web-et-numerique-internet/data.grandlyon.com/web-portal/components/services/postgres-services:${TAG}
ports:
- ${POSTGRES_SERVICE_BIND_PORT}:3000
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_ADMIN_PASSWORD: ${POSTGRES_ADMIN_PASSWORD}
POSTGRES_DB: services
POSTGRES_HOST: database-postgres
POSTGRES_PORT: 5432
GROUP_HEADER: ${GROUP_HEADER}
ADMIN_GROUP_NAME: ${ADMIN_GROUP_NAME}
ACCESS_TOKEN_COOKIE_KEY: ${ACCESS_TOKEN_COOKIE_KEY}
restart: unless-stopped
depends_on:
- database-postgres
database-postgres:
image: bitnami/postgresql:11
environment:
POSTGRESQL_USERNAME: user
POSTGRESQL_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRESQL_DATABASE: services
POSTGRESQL_POSTGRES_PASSWORD : ${POSTGRES_ADMIN_PASSWORD}
restart: unless-stopped
ports:
- ${POSTGRES_PORT}:5432
volumes:
- db-data:/bitnami/postgresql
volumes:
db-data:
favicon.ico

31.3 KiB

{
"language": "ts",
"collection": "@nestjs/schematics",
"sourceRoot": "src"
}
{
"watch": ["src"],
"ext": "ts",
"ignore": ["src/**/*.spec.ts"],
"exec": "node --inspect-brk -r ts-node/register src/main.ts"
}
\ No newline at end of file
{
"watch": ["src"],
"ext": "ts",
"ignore": ["src/**/*.spec.ts"],
"exec": "ts-node -r tsconfig-paths/register src/main.ts"
}
// tslint:disable-next-line:no-var-requires
const dotenv = require('dotenv');
// tslint:disable-next-line:no-var-requires
const fs = require('fs');
let root = 'src';
// For prod build, the files are in a dist folder
if (process.env.PRODBUILD) {
root = 'dist';
}
const ormConfig = {
type: 'postgres',
host: process.env.POSTGRES_HOST,
port: process.env.POSTGRES_PORT,
username: process.env.MIGRATING === '1' ? 'postgres' : process.env.POSTGRES_USER,
password: process.env.MIGRATING === '1' ? process.env.POSTGRES_ADMIN_PASSWORD : process.env.POSTGRES_PASSWORD,
database: process.env.POSTGRES_DB,
entities: [`${root}/**/**.entity{.ts,.js}`],
synchronize: false,
migrations: [`${root}/migrations/*.ts`],
cli: { migrationsDir: `${root}/migrations` },
logging: [
'error',
],
};
module.exports = ormConfig;
This diff is collapsed.
{
"name": "service-postgresql",
"version": "1.0.0",
"description": "Portail Grand Lyon microservices handling credits, organisation and other resources persistence on PostgreSQL database",
"author": "",
"license": "GNU Affero General Public License v3.0",
"scripts": {
"format": "prettier --write \"src/**/*.ts\"",
"start": "ts-node src/index.ts",
"start:dev": "nodemon",
"start:debug": "nodemon --config nodemon-debug.json",
"prestart:prod": "rimraf dist && tsc",
"start:prod": "cross-env PRODBUILD=1 node dist/main.js",
"start:hmr": "node dist/server",
"lint": "tslint -p tsconfig.json -c tslint.json",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:e2e": "jest --config ./test/jest-e2e.json",
"webpack": "webpack --config webpack.config.js",
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config ormconfig.ts",
"typeorm:generate": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:generate -n",
"typeorm:migrate": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:run",
"typeorm:revert": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:revert",
"typeorm:migrate-ci": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:run"
},
"dependencies": {
"@godaddy/terminus": "^4.1.0",
"@nestjs/common": "^7.6.13",
"@nestjs/core": "^7.6.13",
"@nestjs/platform-express": "^7.6.13",
"@nestjs/swagger": "^4.7.13",
"@nestjs/terminus": "^7.1.0",
"@nestjs/typeorm": "^5.2.2",
"@types/dotenv": "^4.0.3",
"amqplib": "^0.5.2",
"class-transformer": "^0.1.9",
"class-validator": "^0.11.0",
"cookie-parser": "^1.4.4",
"cross-env": "^5.2.0",
"dotenv": "^6.1.0",
"jsonwebtoken": "^8.5.1",
"mysql": "^2.14.1",
"pg": "^8.5.1",
"postgresql": "0.0.1",
"reflect-metadata": "^0.1.10",
"rxjs": "^6.2.2",
"serve-favicon": "^2.5.0",
"swagger-ui-express": "^4.1.6",
"typeorm": "0.2.31",
"typescript": "^4.2.2",
"uuid": "^3.3.2"
},
"devDependencies": {
"@nestjs/testing": "^7.6.13",
"@types/amqplib": "^0.5.8",
"@types/express": "^4.16.0",
"@types/jest": "^23.3.14",
"@types/node": "^8.0.29",
"@types/supertest": "^2.0.5",
"jest": "^26.6.3",
"nodemon": "^1.18.3",
"prettier": "^1.14.2",
"rimraf": "^2.6.2",
"supertest": "^3.1.0",
"ts-jest": "^26.5.2",
"ts-loader": "^4.4.2",
"ts-node": "3.3.0",
"tsconfig-paths": "^3.5.0",
"tslint": "5.11.0",
"typescript": "3.3.3333",
"webpack": "^4.16.5",
"webpack-cli": "^4.5.0",
"webpack-node-externals": "^1.7.2"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
import { Logger } from '@nestjs/common';
export class AppLogger extends Logger {
log(message: string, context?: string) {
// add your tailored logic here
super.log(`[log] ${message}`, context);
}
warn(message: string, context?: string) {
// add your tailored logic here
super.warn(`[warn] ${message}`, context);
}
error(message: string, trace?: string, context?: string) {
// add your tailored logic here
super.error(`[error] ${message}`, trace, context);
}
}
import { Module, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { CreditsModule } from './credits/credits.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LinksModule } from './links/links.module';
import { ConfigModule } from './configuration/config.module';
import { HealthModule } from './health/health.module';
import { AppLogger } from './app-logger';
import { APP_GUARD } from '@nestjs/core';
import { GroupsGuard } from './guards/groups.guards';
import { VerifyXsrfTokenAndDecodeJWTPayloadMiddleware } from './middlewares/decode-jwt-payload.middleware';
import { ProjectionController } from './projections/projection.controller';
import { Projection } from './projections/projection.entity';
import { ProjectionService } from './projections/projection.service';
import { ResourceFormatsController } from './resource-formats/resource-format.controller';
import { ResourceFormat } from './resource-formats/resource-format.entity';
import { ResourceFormatsService } from './resource-formats/resource-format.service';
import { ResourcesController } from './resources/resource.controller';
import { Resource } from './resources/resource.entity';
import { ResourcesService } from './resources/resource.service';
import { OrganizationsModule } from './organizations/organizations.module';
import { Format } from './formats/format.entity';
import { FormatService } from './formats/format.service';
import { FormatController } from './formats/format.controller';
@Module({
imports: [
ConfigModule,
TypeOrmModule.forRoot(),
TypeOrmModule.forFeature([Resource]),
TypeOrmModule.forFeature([ResourceFormat]),
TypeOrmModule.forFeature([Format]),
TypeOrmModule.forFeature([Projection]),
LinksModule,
OrganizationsModule,
CreditsModule,
HealthModule,
],
controllers: [
ResourcesController,
ResourceFormatsController,
FormatController,
ProjectionController,
],
providers: [
AppLogger,
ResourcesService,
ResourceFormatsService,
FormatService,
ProjectionService,
{
provide: APP_GUARD,
useClass: GroupsGuard,
},
],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
// Applying the middleware that takes the Authorization header jwt payload and put it in the request headers
consumer
.apply(VerifyXsrfTokenAndDecodeJWTPayloadMiddleware)
.forRoutes(
{ path: 'links', method: RequestMethod.POST },
{ path: 'links/:id', method: RequestMethod.PUT },
{ path: 'links/:id', method: RequestMethod.DELETE },
{ path: 'credits', method: RequestMethod.POST },
{ path: 'credits/:id', method: RequestMethod.PUT },
{ path: 'credits/:id', method: RequestMethod.DELETE },
{ path: 'formats', method: RequestMethod.POST },
{ path: 'formats/:id', method: RequestMethod.PUT },
{ path: 'formats/:id', method: RequestMethod.DELETE },
{ path: 'projections', method: RequestMethod.POST },
{ path: 'projections/:id', method: RequestMethod.PUT },
{ path: 'projections/:id', method: RequestMethod.DELETE },
{ path: 'resourceformats', method: RequestMethod.POST },
{ path: 'resourceformats/:id', method: RequestMethod.PUT },
{ path: 'resourceformats/:id', method: RequestMethod.DELETE },
{ path: 'resources', method: RequestMethod.POST },
{ path: 'resources/:id', method: RequestMethod.PUT },
{ path: 'resources/:id', method: RequestMethod.DELETE },
{ path: 'links', method: RequestMethod.POST },
{ path: 'links/:id', method: RequestMethod.PUT },
{ path: 'links/:id', method: RequestMethod.DELETE },
{ path: 'organizations', method: RequestMethod.POST },
{ path: 'organizations/:id', method: RequestMethod.PUT },
{ path: 'organizations/:id', method: RequestMethod.DELETE },
);
}
}
import { Module, Global } from '@nestjs/common';
import { ConfigService } from './config.service';
@Global()
@Module({
providers: [
{
provide: ConfigService,
useValue: new ConfigService(),
},
],
exports: [ConfigService],
})
export class ConfigModule {}
import * as dotenv from 'dotenv';
import { config } from './config';
export class ConfigService {
private _config = config;
constructor() {
// Initializing conf with values from var env
dotenv.config();
this._config.groupNames.admin = process.env.ADMIN_GROUP_NAME;
this._config.groupHeader = process.env.GROUP_HEADER;
this._config.accessTokenCookieKey = process.env.ACCESS_TOKEN_COOKIE_KEY;
}
get config() {
return this._config;
}
}
export const config = {
groupNames: {
admin: '',
},
groupHeader: '',
accessTokenCookieKey: '',
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment