From 9367571927b632f8fb2b0730ceaef7b036bfc0e3 Mon Sep 17 00:00:00 2001 From: Subhashinie Koshalya Date: Sun, 1 Nov 2020 19:42:14 +0530 Subject: [PATCH 01/12] backend: update readme, reponse to return url, permissions --- backend/readme.md | 8 ++++++++ .../gov/govtech/covid19/controller/ImageController.java | 9 ++++++--- .../lk/gov/govtech/covid19/dto/StoredImageResponse.java | 3 +-- .../govtech/covid19/security/SecurityConfiguration.java | 4 ++++ .../lk/gov/govtech/covid19/service/ImageService.java | 7 ++++++- .../main/java/lk/gov/govtech/covid19/util/Constants.java | 4 ++++ 6 files changed, 29 insertions(+), 6 deletions(-) diff --git a/backend/readme.md b/backend/readme.md index 6b0a320..df8192f 100644 --- a/backend/readme.md +++ b/backend/readme.md @@ -10,6 +10,12 @@ mvn clean package cd target java -jar backend.jar ``` +## Context of the Backend +The context of the backend is `/api`. This is set at `server.servlet.context-path` in +the application.yaml. Since we serve the backend at `/api`, every controller context +path is appended after `/api`. eg: `https://host/api/notification`. +The admin portal ui to the backend is served at `/` as a seperate web app. +Similarly, backend is another webapp served at `/api` in the same tomcat. ## How the Portal Webapp is Served in the Tomcat Server - pom.xml in `portal/` will build the vue app and will create a war, by including everything inside `dist` @@ -19,4 +25,6 @@ java -jar backend.jar - if none of them exists, backend will start without the webapp - For more info: `lk.gov.govtech.covid19.config.WebappConfiguration` - Content in the war will appear at localhost:8000/ + + \ No newline at end of file diff --git a/backend/src/main/java/lk/gov/govtech/covid19/controller/ImageController.java b/backend/src/main/java/lk/gov/govtech/covid19/controller/ImageController.java index f3b4dc8..10005a2 100644 --- a/backend/src/main/java/lk/gov/govtech/covid19/controller/ImageController.java +++ b/backend/src/main/java/lk/gov/govtech/covid19/controller/ImageController.java @@ -4,6 +4,7 @@ import lk.gov.govtech.covid19.dto.StoredImageResponse; import lk.gov.govtech.covid19.service.ImageService; import lk.gov.govtech.covid19.util.Constants; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -11,22 +12,24 @@ import org.springframework.web.multipart.MultipartFile; @RestController +@Slf4j @RequestMapping(Constants.IMAGE_API_CONTEXT) public class ImageController { @Autowired ImageService imageService; - @PostMapping(path = "/add") + @PostMapping public ResponseEntity uploadImage(@RequestParam("image") MultipartFile image){ StoredImageResponse response = null; if (image.isEmpty()){ - System.out.println("empty file"); + log.info("Request does not contain an image"); }else { + log.info("Image {} of size:{} being added", image.getOriginalFilename(), image.getSize()); response = imageService.addImage(image); } System.gc(); - return ResponseEntity.ok().body(response); + return ResponseEntity.accepted().body(response); } @GetMapping(value = "/image/{imageId}", produces = MediaType.IMAGE_JPEG_VALUE) diff --git a/backend/src/main/java/lk/gov/govtech/covid19/dto/StoredImageResponse.java b/backend/src/main/java/lk/gov/govtech/covid19/dto/StoredImageResponse.java index ed9fa02..2959857 100644 --- a/backend/src/main/java/lk/gov/govtech/covid19/dto/StoredImageResponse.java +++ b/backend/src/main/java/lk/gov/govtech/covid19/dto/StoredImageResponse.java @@ -1,11 +1,10 @@ package lk.gov.govtech.covid19.dto; -import lombok.AllArgsConstructor; import lombok.Data; @Data -@AllArgsConstructor public class StoredImageResponse { private int id; + private String url; private String name; } diff --git a/backend/src/main/java/lk/gov/govtech/covid19/security/SecurityConfiguration.java b/backend/src/main/java/lk/gov/govtech/covid19/security/SecurityConfiguration.java index b7134ec..4336d91 100644 --- a/backend/src/main/java/lk/gov/govtech/covid19/security/SecurityConfiguration.java +++ b/backend/src/main/java/lk/gov/govtech/covid19/security/SecurityConfiguration.java @@ -31,6 +31,8 @@ public class SecurityConfiguration { /* * Endpoints with auth (either http basic auth or login based can be used) * - /notification + * - /application PUT + * - /images POST * * */ @@ -102,6 +104,8 @@ protected void configure(final HttpSecurity http) throws Exception { .hasAuthority(AUTHORITY_NOTIFICATION) .antMatchers(HttpMethod.PUT, APPLICATION_API_CONTEXT + "/dashboard/status") .hasAuthority(AUTHORITY_NOTIFICATION) + .antMatchers(HttpMethod.POST, IMAGE_API_CONTEXT) + .hasAuthority(AUTHORITY_NOTIFICATION) .and() .addFilter(getPasswordFilter()) .requestCache() // avoid saving anonymous requests in sessions diff --git a/backend/src/main/java/lk/gov/govtech/covid19/service/ImageService.java b/backend/src/main/java/lk/gov/govtech/covid19/service/ImageService.java index 0d9d758..7348913 100644 --- a/backend/src/main/java/lk/gov/govtech/covid19/service/ImageService.java +++ b/backend/src/main/java/lk/gov/govtech/covid19/service/ImageService.java @@ -3,6 +3,7 @@ import lk.gov.govtech.covid19.dto.StoredImage; import lk.gov.govtech.covid19.dto.StoredImageResponse; import lk.gov.govtech.covid19.repository.CovidRepository; +import lk.gov.govtech.covid19.util.Constants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -28,7 +29,11 @@ public StoredImageResponse addImage(MultipartFile file){ byte[] bArray = imageCompressionService.compressImage(file); InputStream is = new ByteArrayInputStream(bArray); int id = repository.addImage(is,file.getOriginalFilename(),file.getSize()); - storedImageResponse = new StoredImageResponse(id,file.getOriginalFilename()); + storedImageResponse = new StoredImageResponse(); + storedImageResponse.setId(id); + storedImageResponse.setUrl(Constants.BACKEND_CONTEXT + + Constants.IMAGE_API_CONTEXT + "/image/" + id); + storedImageResponse.setName(file.getOriginalFilename()); return storedImageResponse; } catch (FileNotFoundException e) { e.printStackTrace(); diff --git a/backend/src/main/java/lk/gov/govtech/covid19/util/Constants.java b/backend/src/main/java/lk/gov/govtech/covid19/util/Constants.java index 2f824a4..298b9e4 100644 --- a/backend/src/main/java/lk/gov/govtech/covid19/util/Constants.java +++ b/backend/src/main/java/lk/gov/govtech/covid19/util/Constants.java @@ -2,6 +2,10 @@ public class Constants { + //although defined here, actually set at `server.servlet.context-path` in + //the application.yaml file. Refer to backend/readme for more info + public static final String BACKEND_CONTEXT = "/api"; + //context for all calls related to task force ap public static final String TF_API_CONTEXT = "/taskforce"; //context for all calls related to dhis service integration From 81d4ed3728c6cc8c3457673eb1dbc9aceb5fdf9a Mon Sep 17 00:00:00 2001 From: Subhashinie Koshalya Date: Sun, 1 Nov 2020 19:43:43 +0530 Subject: [PATCH 02/12] portal: update editor to upload and preview image --- portal/src/api/index.js | 11 +++++++++ portal/src/components/views/news/News.vue | 29 ++++++++++++++++++++++ portal/src/components/views/news/news.js | 30 ++++++++++++++++++++++- 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/portal/src/api/index.js b/portal/src/api/index.js index 76bd873..2983ea1 100644 --- a/portal/src/api/index.js +++ b/portal/src/api/index.js @@ -44,4 +44,15 @@ export default { } }) }, + postMultipartFDWithToken(url, data) { + return axios({ + method: 'post', + url: '/api' + url, + data: data, + headers: { + 'content-type': 'multipart/form-data', + 'x-auth-token': store.getters['user/getToken'] + } + }) + }, } \ No newline at end of file diff --git a/portal/src/components/views/news/News.vue b/portal/src/components/views/news/News.vue index d4d39f3..52a1b68 100644 --- a/portal/src/components/views/news/News.vue +++ b/portal/src/components/views/news/News.vue @@ -184,6 +184,16 @@ + + @@ -356,6 +366,15 @@ + @@ -521,6 +540,16 @@ + + diff --git a/portal/src/components/views/news/news.js b/portal/src/components/views/news/news.js index 0dd38ec..d672fb7 100644 --- a/portal/src/components/views/news/news.js +++ b/portal/src/components/views/news/news.js @@ -15,6 +15,7 @@ import { Strike, Underline, History, + Image, } from 'tiptap-extensions' import api from '../../../api' @@ -43,6 +44,7 @@ export default { new Strike(), new Underline(), new History(), + new Image(), ], onUpdate: ({getHTML}) => { this.message.english = getHTML(); @@ -65,6 +67,7 @@ export default { new Strike(), new Underline(), new History(), + new Image(), ], onUpdate: ({getHTML}) => { this.message.sinhala = getHTML(); @@ -87,6 +90,7 @@ export default { new Strike(), new Underline(), new History(), + new Image(), ], onUpdate: ({getHTML}) => { this.message.tamil = getHTML(); @@ -107,6 +111,7 @@ export default { "bullet_list":"Bullet List", "redo":"Redo", "undo":"UnDo", + "image":"Image", }, "source":'', @@ -215,6 +220,7 @@ export default { new Strike(), new Underline(), new History(), + new Image(), ], onUpdate: ({getHTML}) => { this.message.english = getHTML(); @@ -236,6 +242,7 @@ export default { new Strike(), new Underline(), new History(), + new Image(), ], onUpdate: ({getHTML}) => { this.message.english = getHTML(); @@ -257,6 +264,7 @@ export default { new Strike(), new Underline(), new History(), + new Image(), ], onUpdate: ({getHTML}) => { this.message.english = getHTML(); @@ -289,6 +297,26 @@ export default { tamilChar() { this.charcount.tamilChar = (this.message.tamil.length)-7; - } + }, + showImagePrompt(commands) { + let inputElement = document.createElement("input"); + inputElement.setAttribute("type", "file"); + inputElement.addEventListener('change', (e) => { + if (e.target.files && e.target.files[0]) { + let anImage = e.target.files[0]; // file from input + + let formData = new FormData(); + formData.append("image", anImage, anImage.name); + api.postMultipartFDWithToken('/images', formData) + .then(response=>{ + if(response.status == 202 && response.data.url.length>0){ + const src = response.data.url; + commands.image({ src }); + } + }); + } + }) + inputElement.click(); + }, } } From b7ccce0953cf5b2d494f8d80b74c8096fd0390cf Mon Sep 17 00:00:00 2001 From: Subhashinie Koshalya Date: Mon, 2 Nov 2020 19:48:26 +0530 Subject: [PATCH 03/12] portal: new component NewsEditor --- portal/public/index.html | 1 - portal/src/components/views/news/News.vue | 31 +-- .../src/components/views/news/NewsEditor.vue | 261 ++++++++++++++++++ portal/src/components/views/news/news.js | 102 ++++--- 4 files changed, 322 insertions(+), 73 deletions(-) create mode 100644 portal/src/components/views/news/NewsEditor.vue diff --git a/portal/public/index.html b/portal/public/index.html index af3e6c5..928948b 100644 --- a/portal/public/index.html +++ b/portal/public/index.html @@ -22,7 +22,6 @@ MyHealth Sri Lanka Management Portal-login - diff --git a/portal/src/components/views/news/News.vue b/portal/src/components/views/news/News.vue index 52a1b68..cae83eb 100644 --- a/portal/src/components/views/news/News.vue +++ b/portal/src/components/views/news/News.vue @@ -44,10 +44,10 @@
- -
+ +
@@ -229,7 +222,7 @@
-