diff --git a/docker-compose-prod.yml b/docker-compose-prod.yml deleted file mode 100644 index 60dc267a6..000000000 --- a/docker-compose-prod.yml +++ /dev/null @@ -1,75 +0,0 @@ -version: '3.6' -services: - api: - image: ${CONTAINER_IMAGE:-backend} - volumes: - - uploads_volume:/usr/src/app/uploads - depends_on: - - db - environment: - NODE_ENV: production - PORT: 3000 - DB_HOST: db - DB_USER: postgres - DB_NAME: say_dapp - DB_PASS_FILE: /run/secrets/postgres-password - secrets: - - postgres-password - networks: - - default - - traefik-public - deploy: - replicas: 1 - update_config: - parallelism: 1 - order: start-first - placement: - constraints: - - node.labels.${ENVIRONMENT} == true - mode: replicated - labels: - - traefik.enable=true - - traefik.docker.network=traefik-public - - traefik.constraint-label=traefik-public - - traefik.http.routers.${STACK_NAME}-api-http.entrypoints=http - - traefik.http.routers.${STACK_NAME}-api-http.rule=Host(`${DOMAIN?Variable not set}`) - - traefik.http.routers.${STACK_NAME}-api-http.service=${STACK_NAME}-api - - traefik.http.routers.${STACK_NAME}-api-http.middlewares=https-redirect - - traefik.http.routers.${STACK_NAME}-api.entrypoints=https - - traefik.http.routers.${STACK_NAME}-api.rule=Host(`${DOMAIN?Variable not set}`) - - traefik.http.routers.${STACK_NAME}-api.service=${STACK_NAME}-api - - traefik.http.routers.${STACK_NAME}-api.tls=true - - traefik.http.routers.${STACK_NAME}-api.tls.certresolver=le - - traefik.http.services.${STACK_NAME}-api.loadbalancer.server.port=3000 - - db: - image: postgres:12 - secrets: - - postgres-password - environment: - POSTGRES_DB: say_dapp - POSTGRES_USER: postgres - POSTGRES_PASSWORD_FILE: /run/secrets/postgres-password - volumes: - - postgres_volume:/var/lib/postgresql/data - deploy: - replicas: 1 - update_config: - parallelism: 1 - order: stop-first - placement: - constraints: - - node.labels.${ENVIRONMENT} == true - -volumes: - postgres_volume: - uploads_volume: - -networks: - traefik-public: - external: true - -secrets: - postgres-password: - name: ${STACK_NAME}-postgres-password - external: true diff --git a/docker-compose.production.yml b/docker-compose.production.yml index f06094421..3f890d79c 100644 --- a/docker-compose.production.yml +++ b/docker-compose.production.yml @@ -49,7 +49,7 @@ services: - postgres-password environment: POSTGRES_DB: say_dapp - POSTGRES_USER: postgres + POSTGRES_USER: nestserver POSTGRES_PASSWORD_FILE: /run/secrets/postgres-password volumes: - postgres_volume:/var/lib/postgresql/data @@ -64,9 +64,9 @@ services: volumes: postgres_volume: - name: "say-nest1_postgres_volume" + name: "${STACK_NAME}_postgres_volume" uploads_volume: - name: "say-nest1_uploads_volume" + name: "${STACK_NAME}_uploads_volume" networks: traefik-public: diff --git a/package.json b/package.json index 0f3c595b3..f7a623fcf 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@discord-nestjs/common": "*", "@discord-nestjs/core": "*", "@fleekhq/fleek-storage-js": "^1.0.24", + "@getvim/execute": "^1.0.0", "@nestjs-modules/mailer": "^1.9.1", "@nestjs/axios": "^3.0.1", "@nestjs/common": "^10.1.3", diff --git a/src/config.ts b/src/config.ts index 22a2bbae2..c188ebf8c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -27,7 +27,7 @@ function loadConfig() { documentUrl: '', db1: { type: 'postgres' as const, - port: 5432, + port: Number(process.env.DB_PORT), host: NODE_ENV === 'development' ? 'localhost' : process.env.DB_HOST, username: process.env.DB_USER ?? 'postgres', password: process.env.DB_PASS ?? 'postgres', @@ -44,7 +44,7 @@ function loadConfig() { db2: { name: 'flaskPostgres', type: 'postgres' as const, - port: 35432, + port: Number(process.env.DB_FLASK_PORT), host: process.env.DB_FLASK_HOST, username: process.env.DB_FLASK_USER, password: process.env.DB_FLASK_PASS, diff --git a/src/features/payment/payment.controller.ts b/src/features/payment/payment.controller.ts index 84b14ecdf..e1da53f00 100644 --- a/src/features/payment/payment.controller.ts +++ b/src/features/payment/payment.controller.ts @@ -1,14 +1,18 @@ import { + Body, Controller, ForbiddenException, Get, Param, + Post, Req, } from '@nestjs/common'; import { ApiHeader, ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger'; import { PaymentService } from './payment.service'; import { isAuthenticated } from 'src/utils/auth'; import { FlaskUserTypesEnum } from 'src/types/interfaces/interface'; +import config from 'src/config'; +import axios from 'axios'; @ApiTags('Payments') @ApiSecurity('flask-access-token') @@ -19,20 +23,48 @@ import { FlaskUserTypesEnum } from 'src/types/interfaces/interface'; }) @Controller('payment') export class PaymentController { - constructor(private paymentService: PaymentService) { } + constructor(private paymentService: PaymentService) {} - @Get(`new`) + @Post(`new`) @ApiOperation({ description: 'Get all needs payments' }) - async newPayments(@Req() req: Request) { - const panelFlaskUserId = req.headers['panelFlaskUserId']; - const panelFlaskTypeId = req.headers['panelFlaskTypeId']; - if ( - !isAuthenticated(panelFlaskUserId, panelFlaskTypeId) || - panelFlaskTypeId !== FlaskUserTypesEnum.SUPER_ADMIN - ) { - throw new ForbiddenException('You Are not the Super admin'); + async newPayments( + @Req() req: Request, + @Body() + body: { + needId: number; + gateway: number; + amount: number; + donate: number; + useCredit: boolean; + }, + ) { + const dappFlaskUserId = Number(req.headers['dappFlaskUserId']); + + if (!isAuthenticated(dappFlaskUserId, FlaskUserTypesEnum.FAMILY)) { + throw new ForbiddenException('You Are not authorized'); } - return await this.paymentService.getPayments(); + + const token = + config().dataCache.fetchPanelAuthentication(dappFlaskUserId).token; + const configs = { + headers: { + 'Content-Type': 'application/json', + Authorization: token, + }, + }; + + // create flask child + // const { data } = await axios.post( + // 'https://api.sayapp.company/api/v2/child/add/', + // { + // needId: body.amount, + // amount: body.amount, + // donate: body.donate, + // useCredit: body.useCredit, + // }, + // configs, + // ); + console.log(body); } @Get(`all`) diff --git a/src/features/schedule/backup.js b/src/features/schedule/backup.js new file mode 100644 index 000000000..143069912 --- /dev/null +++ b/src/features/schedule/backup.js @@ -0,0 +1,55 @@ +import { execute } from "@getvim/execute"; +import 'dotenv/config'; + +console.log('Backing up data base using ~.pgpass file...'); + +// getting db connection parameters from environment file +const username = process.env.DB_FLASK_USER; +const database = process.env.DB_FLASK_NAME; +const dbHost = process.env.DB_FLASK_HOST; +const dbPort = process.env.DB_FLASK_PORT; + +// defining backup file name +const date = new Date(); +const today = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`; +const backupFile = `../../backup/flask/pg-flask-backup-${today}.tar`; + +// writing postgresql backup function +const takePGBackup = () => { + execute( + `pg_dump -U ${username} -h ${dbHost} -p ${dbPort} -f ${backupFile} -F t -d ${database} -v`, + ).then(async () => { + console.log(`Backup created successfully`); + }).catch((err) => { + console.log(err); + }); +}; + +const getListOfFiles = () => { + execute( + `pg_restore -l -f list.toc db.dump`, + ).then(async () => { + console.log(`Backup created successfully`); + }).catch((err) => { + console.log(err); + }); +}; + +function sendToBackupServer(fileName = fileNameGzip) { + const form = new FormData(); + form.append('file', fileName); + axios.post('', form, { headers: form.getHeaders(), }).then(result => { + // Handle result… + fs.unlinkSync(fileNameGzip); + console.log(result.data); + }).catch(err => { + console.error(err); + }); +} + + +// First, get the TOC list of objects to be restored: +// getListOfFiles(); + +// calling postgresql backup function +takePGBackup(); diff --git a/src/features/schedule/schedule.service.ts b/src/features/schedule/schedule.service.ts index 3da06dc7e..2096d3559 100644 --- a/src/features/schedule/schedule.service.ts +++ b/src/features/schedule/schedule.service.ts @@ -6,6 +6,7 @@ import { FamilyService } from '../family/family.service'; import { AnalyticService } from '../analytic/analytic.service'; import { CampaignService } from '../campaign/campaign.service'; import { persianDay } from 'src/utils/helpers'; +import { execute } from '@getvim/execute'; @Injectable() export class ScheduleService { @@ -172,30 +173,64 @@ export class ScheduleService { await this.campaignService.sendSwAnnounceReminder(); } } - // @Cron('30 8 * * Sat', { - // name: 'Confirm Needs At 08:30 on Saturday.', - // timeZone: 'Asia/Tehran', - // }) - // @Timeout(5000) - // async handleNeedConfirmCron() { - // this.logger.debug('Confirming Needs ...'); - // const swIds = await this.userService - // .getFlaskSwIds() - // .then((r) => r.map((s) => s.id)); - - // const ngoIds = await this.ngoService - // .getFlaskNgos() - // .then((r) => r.map((s) => s.id)); - - // const toBeConfirmed = await this.needService.getNotConfirmedNeeds( - // null, - // swIds, - // ngoIds, - // ); - // for await (const need of toBeConfirmed[0]) { - // const duplicates = await this.needService.getDuplicateNeeds(need.child_id, need.id); - // } - - // console.log(toBeConfirmed[1]); - // } + + @Cron('00 10 * * *', { + name: 'Reminders to announce arrivals At 10:00 everyday.', + timeZone: 'Asia/Tehran', + }) + async handleNeedConfirmCron() { + if (process.env.NODE_ENV === 'development') { + this.logger.debug('Backing up data base ...'); + + // getting db connection parameters from environment file + const username_flask = process.env.DB_FLASK_USER; + const database_flask = process.env.DB_FLASK_NAME; + const dbHost_flask = process.env.DB_FLASK_HOST; + const dbPort_flask = process.env.DB_FLASK_PORT; + + const username_nest = process.env.DB_USER; + const database_nest = process.env.DB_NAME; + const dbPort_nest = 3000; + + // defining backup file name + const date = new Date(); + const today = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`; + const backupFileFlask = `../../backup/flask/pg-flask-backup-${today}.tar`; + const backupFileNest = `../../backup/nest/pg-nest-backup-${today}.tar`; + + // flask + const flaskPGBackup = () => { + execute( + `pg_dump -U ${username_flask} -h ${dbHost_flask} -p ${dbPort_flask} -f ${backupFileFlask} -F t -d ${database_flask}`, + ) + .then(async () => { + console.log(`Backup created successfully`); + }) + .catch((err) => { + console.log(err); + }); + }; + + //nest + const nestPGBackup = () => { + console.log( + `pg_dump -U ${username_nest} -h ${dbHost_flask} -p ${dbPort_nest} -f ${backupFileNest} -F t -d ${database_nest}`, + ); + + execute( + `pg_dump -U ${username_nest} -h ${dbHost_flask} -p ${dbPort_nest} -f ${backupFileNest} -F t -d ${database_nest}`, + ) + .then(async () => { + console.log(`Backup created successfully`); + }) + .catch((err) => { + console.log(err); + }); + }; + + // calling postgresql backup function + // nestPGBackup(); + flaskPGBackup(); + } + } } diff --git a/tsconfig.json b/tsconfig.json index 04cd37611..fe4fd5d8a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,5 +22,5 @@ "useDefineForClassFields": true, // for discord package }, "include": ["src/**/*"], - "exclude": ["node_modules", "**/*.spec.ts", "src/test.js"] + "exclude": ["node_modules", "**/*.spec.ts", "src/test.js", "src/features/schedule/backup.js"] }