From 324e6743d81f1188be920cf6721e897c67dbfbaf Mon Sep 17 00:00:00 2001
From: Danny <danny.mhlv@gmail.com>
Date: Mon, 21 Nov 2022 20:25:26 +0300
Subject: [PATCH] Paper 'upload' endpoint implemented

---
 elastic/scripts/es_boot.sh                    |  2 +-
 .../controller/papers.controller.ts           | 32 ++++++++++++-
 src/core/domain/dtos/paper.dto.ts             |  2 +-
 src/core/services/common/search.service.ts    |  4 +-
 src/core/services/common/upload.service.ts    | 48 +++++++++++++++++++
 src/infrastructure/modules/app.module.ts      |  4 +-
 src/infrastructure/modules/index.ts           |  3 +-
 .../{search.module.ts => papers.module.ts}    |  7 +--
 8 files changed, 89 insertions(+), 13 deletions(-)
 create mode 100644 src/core/services/common/upload.service.ts
 rename src/infrastructure/modules/{search.module.ts => papers.module.ts} (65%)

diff --git a/elastic/scripts/es_boot.sh b/elastic/scripts/es_boot.sh
index 77c9650..154a7fa 100755
--- a/elastic/scripts/es_boot.sh
+++ b/elastic/scripts/es_boot.sh
@@ -3,7 +3,7 @@
 __isint='^[0-9]+$'
 __isvalidstr='^[a-z0-9]+$'
 __isvalidaddr='^[a-z]+$|^((25[0-5]|2[0-4]?[0-9]|1[0-9]?[0-9]|[3-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4]?[0-9]|1[0-9]?[0-9]|[3-9][0-9]|[0-9])$'
-__isJSONfile='^[a-z0-9\_\-]+(\.json)$'
+__isJSONfile='^[-_\/a-zA-Z\.]+(\.json){1}$'
 
 create_template() {
     curl -H "Content-Type: application/json" -X PUT "$1:$2/_index_template/papers_t" -d @"$3"
diff --git a/src/application/controller/papers.controller.ts b/src/application/controller/papers.controller.ts
index 04c6531..af725c2 100644
--- a/src/application/controller/papers.controller.ts
+++ b/src/application/controller/papers.controller.ts
@@ -1,9 +1,10 @@
-import { Controller, Get, HttpCode, Param, ParseUUIDPipe, Query, UseFilters, UseInterceptors } from "@nestjs/common";
+import { Body, Controller, Get, HttpCode, Param, ParseUUIDPipe, Post, Put, Query, UseFilters, UseInterceptors } from "@nestjs/common";
 import { SearchService } from "../../core/services/common/search.service";
 import { PageInterceptor } from "../../core/interceptors/page.interceptor";
 import { ApiExtraModels, ApiGatewayTimeoutResponse, ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
 import { EsHitDto, EsResponseDto, PageDto, PaperDto, SearchQueryDto } from "../../core/domain";
 import { HttpExceptionFilter } from "../../core/filters/http-exception.filter";
+import { UploadService } from "../../core/services/common/upload.service";
 
 /**
  * /papers/ route controller
@@ -15,7 +16,10 @@ import { HttpExceptionFilter } from "../../core/filters/http-exception.filter";
 })
 @ApiExtraModels(EsHitDto, EsResponseDto)
 export class PapersController {
-    constructor(private searchService: SearchService) {}
+    constructor(
+        private searchService: SearchService,
+        private uploadService: UploadService
+    ) {}
 
     /**
      * Request handler for: GET /papers/search
@@ -80,4 +84,28 @@ export class PapersController {
             }
         );
     }
+
+    /**
+     * Request handler for PUT /papers/upload
+     * @param uuid 
+     * @param response 
+     * @returns a response with a requested object
+     */
+    @ApiTags('Upload')
+    @ApiOperation({ 
+        summary: 'Uploads paper',
+        tags: ['Upload']
+    })
+    @Put('upload')
+    uploadPaper(@Body() paperData: PaperDto) {
+        console.log('gdgdgdgd')
+       return this.uploadService.upload(paperData).then(
+            (response) => {
+                return response;
+            },
+            (error) => {
+                throw error;
+            }
+       )
+    }
 }
\ No newline at end of file
diff --git a/src/core/domain/dtos/paper.dto.ts b/src/core/domain/dtos/paper.dto.ts
index 07e1d7d..8986b9f 100644
--- a/src/core/domain/dtos/paper.dto.ts
+++ b/src/core/domain/dtos/paper.dto.ts
@@ -1,5 +1,5 @@
 import { ApiExtraModels, ApiProperty } from "@nestjs/swagger";
-import { IsArray, IsDefined, IsIn, IsInt, IsNotEmpty, IsOptional, IsString } from "class-validator";
+import { IsArray, IsNotEmpty, IsString } from "class-validator";
 
 /**
  * List of allowed properties in this DTO
diff --git a/src/core/services/common/search.service.ts b/src/core/services/common/search.service.ts
index 7e5a47c..8faa2fc 100644
--- a/src/core/services/common/search.service.ts
+++ b/src/core/services/common/search.service.ts
@@ -1,8 +1,8 @@
 import { HttpService } from "@nestjs/axios";
-import { GatewayTimeoutException, ImATeapotException, Injectable, NotFoundException } from "@nestjs/common";
+import { GatewayTimeoutException, Injectable, NotFoundException } from "@nestjs/common";
 import { map, take } from "rxjs";
 import { EsMultimatchQueryDto } from "src/core/domain/dtos/elastic/es-multimatch.dto";
-import { EsResponseDto, SearchQueryDto} from "../../domain/dtos";
+import { EsResponseDto, SearchQueryDto } from "../../domain/dtos";
 import { EsQueryDto } from "../../domain/dtos/elastic/es-query.dto";
 
 /**
diff --git a/src/core/services/common/upload.service.ts b/src/core/services/common/upload.service.ts
new file mode 100644
index 0000000..9e51628
--- /dev/null
+++ b/src/core/services/common/upload.service.ts
@@ -0,0 +1,48 @@
+import { HttpService } from "@nestjs/axios";
+import { Injectable } from "@nestjs/common";
+import { map, take } from "rxjs";
+import { PaperDto } from "../../domain/dtos";
+
+/**
+ * Upload service provider
+ */
+@Injectable()
+export class UploadService {
+    /**
+     * Constructs the service with injection of
+     * HTTPService instance
+     * @param httpService 
+     */
+    constructor(private readonly httpService: HttpService) {}
+
+    /**
+     * Elastichsearch server port-number
+     */
+    private readonly ES_PORT = process.env.ES_PORT;
+    
+    /**
+     * Elasticsearch IP address
+     */
+    private readonly ES_IP = process.env.ES_CONTAINER_NAME;
+    
+    /**
+     * Uploads a paper
+     * @returns
+     */
+    async upload(paperData: PaperDto): Promise<Object | any> {
+        return new Promise((resolve, reject) => {
+            try {
+                (this.httpService.post(`http://${this.ES_IP}:${this.ES_PORT}/papers/_doc/`, {
+                    data: paperData,
+                    headers: {'Content-Type': 'application/json'},
+                }))
+                ?.pipe(take(1), map(axiosRes => axiosRes.data))
+                .subscribe((res: Object | any) => {
+                    resolve(res);
+                });
+            } catch (error) {
+                reject(error);
+            }
+        });
+    }
+}
\ No newline at end of file
diff --git a/src/infrastructure/modules/app.module.ts b/src/infrastructure/modules/app.module.ts
index 1eefb80..b671d54 100644
--- a/src/infrastructure/modules/app.module.ts
+++ b/src/infrastructure/modules/app.module.ts
@@ -7,7 +7,7 @@ import { LoggerInterceptor } from '../../core/interceptors'
 import * as modules from '../../core/modules'
 import { CommonModule } from './common/common.module';
 import { PrometheusModule } from '@willsoto/nestjs-prometheus';
-import { SearchModule } from './search.module';
+import { PapersModule } from './papers.module';
 
 /**
  * application modules list
@@ -19,7 +19,7 @@ const modulesList = Object.keys(modules).map(moduleIndex => modules[moduleIndex
  */
 @Module({
   imports: [
-    SearchModule,
+    PapersModule,
     PrometheusModule.register(),
     CacheModule.register(),
     CommonModule,
diff --git a/src/infrastructure/modules/index.ts b/src/infrastructure/modules/index.ts
index c80e102..ab275d9 100644
--- a/src/infrastructure/modules/index.ts
+++ b/src/infrastructure/modules/index.ts
@@ -1,2 +1 @@
-export * from './app.module';
-export * from './search.module'
\ No newline at end of file
+export * from './app.module';
\ No newline at end of file
diff --git a/src/infrastructure/modules/search.module.ts b/src/infrastructure/modules/papers.module.ts
similarity index 65%
rename from src/infrastructure/modules/search.module.ts
rename to src/infrastructure/modules/papers.module.ts
index 8fd2f60..33747ba 100644
--- a/src/infrastructure/modules/search.module.ts
+++ b/src/infrastructure/modules/papers.module.ts
@@ -2,6 +2,7 @@ import { HttpModule } from "@nestjs/axios";
 import { CacheModule, Module } from "@nestjs/common";
 import { PapersController } from "../../application";
 import { SearchService } from "../../core/services/common/search.service";
+import { UploadService } from "../../core/services/common/upload.service";
 
 /**
  * Search module
@@ -11,8 +12,8 @@ import { SearchService } from "../../core/services/common/search.service";
         HttpModule,
         CacheModule.register(),
     ],
-    exports: [SearchService],
-    providers: [SearchService],
+    exports: [SearchService, UploadService],
+    providers: [SearchService, UploadService],
     controllers: [PapersController],
 })
-export class SearchModule {}
\ No newline at end of file
+export class PapersModule {}
\ No newline at end of file