diff --git a/pom.xml b/pom.xml
index 99309cc..0a8cddd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -109,6 +109,18 @@
jsoup
1.18.1
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.17.2
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.17.2
+
diff --git a/src/main/java/com/safeqr/app/gmail/controller/GmailController.java b/src/main/java/com/safeqr/app/gmail/controller/GmailController.java
index 08b55e2..de72cd3 100644
--- a/src/main/java/com/safeqr/app/gmail/controller/GmailController.java
+++ b/src/main/java/com/safeqr/app/gmail/controller/GmailController.java
@@ -1,6 +1,7 @@
package com.safeqr.app.gmail.controller;
import com.google.api.services.gmail.model.*;
+import com.safeqr.app.gmail.dto.ScannedGmailResponseDto;
import org.apache.commons.codec.binary.Base64;
import org.json.JSONObject;
import com.google.api.client.auth.oauth2.AuthorizationCodeRequestUrl;
@@ -106,7 +107,7 @@ public class GmailController {
return new ResponseEntity<>("Access token is missing", HttpStatus.BAD_REQUEST);
}
- return new ResponseEntity<>(gmailService.getEmail(accessToken).toString(), HttpStatus.OK);
+ return new ResponseEntity<>(gmailService.getEmail(accessToken), HttpStatus.OK);
}
}
diff --git a/src/main/java/com/safeqr/app/gmail/dto/ScannedGmailResponseDto.java b/src/main/java/com/safeqr/app/gmail/dto/ScannedGmailResponseDto.java
new file mode 100644
index 0000000..07e2f85
--- /dev/null
+++ b/src/main/java/com/safeqr/app/gmail/dto/ScannedGmailResponseDto.java
@@ -0,0 +1,15 @@
+package com.safeqr.app.gmail.dto;
+
+import com.safeqr.app.gmail.model.EmailMessage;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Builder
+@Data
+@AllArgsConstructor
+public class ScannedGmailResponseDto {
+ List messages;
+}
diff --git a/src/main/java/com/safeqr/app/gmail/model/EmailMessage.java b/src/main/java/com/safeqr/app/gmail/model/EmailMessage.java
new file mode 100644
index 0000000..5dfb87d
--- /dev/null
+++ b/src/main/java/com/safeqr/app/gmail/model/EmailMessage.java
@@ -0,0 +1,38 @@
+package com.safeqr.app.gmail.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+@Data
+public class EmailMessage {
+ private String messageId;
+ private String subject;
+ private String historyId;
+
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ List qrCodeByContentId;
+
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ List qrCodeByURL;
+
+ public EmailMessage(String messageId, String subject, String historyId) {
+ this.messageId = messageId;
+ this.subject = subject;
+ this.historyId = historyId;
+ this.qrCodeByContentId = new ArrayList<>();
+ this.qrCodeByURL = new ArrayList<>();
+ }
+ public void addQRCodeByContentId(QRCodeByContentId qrCode) {
+ this.qrCodeByContentId.add(qrCode);
+ }
+
+ public void addQRCodeByURL(QRCodeByURL qrCode) {
+ this.qrCodeByURL.add(qrCode);
+ }
+
+ public boolean hasQRCodes() {
+ return !qrCodeByContentId.isEmpty() || !qrCodeByURL.isEmpty();
+ }
+}
diff --git a/src/main/java/com/safeqr/app/gmail/model/QRCodeByContentId.java b/src/main/java/com/safeqr/app/gmail/model/QRCodeByContentId.java
new file mode 100644
index 0000000..d26e8cd
--- /dev/null
+++ b/src/main/java/com/safeqr/app/gmail/model/QRCodeByContentId.java
@@ -0,0 +1,17 @@
+package com.safeqr.app.gmail.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+@AllArgsConstructor
+public class QRCodeByContentId {
+ private String cid;
+ private String attachmentId;
+ private List decodedContent;
+ private int totalQRCodeFound;
+}
diff --git a/src/main/java/com/safeqr/app/gmail/model/QRCodeByURL.java b/src/main/java/com/safeqr/app/gmail/model/QRCodeByURL.java
new file mode 100644
index 0000000..1a5db08
--- /dev/null
+++ b/src/main/java/com/safeqr/app/gmail/model/QRCodeByURL.java
@@ -0,0 +1,17 @@
+package com.safeqr.app.gmail.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+@AllArgsConstructor
+public class QRCodeByURL {
+ private String url;
+ private List decodedContent;
+ private int totalQRCodeFound;
+
+}
diff --git a/src/main/java/com/safeqr/app/gmail/service/GmailService.java b/src/main/java/com/safeqr/app/gmail/service/GmailService.java
index c1ba153..c3b8599 100644
--- a/src/main/java/com/safeqr/app/gmail/service/GmailService.java
+++ b/src/main/java/com/safeqr/app/gmail/service/GmailService.java
@@ -7,9 +7,11 @@ import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.multi.qrcode.QRCodeMultiReader;
+import com.safeqr.app.gmail.dto.ScannedGmailResponseDto;
+import com.safeqr.app.gmail.model.EmailMessage;
+import com.safeqr.app.gmail.model.QRCodeByContentId;
+import com.safeqr.app.gmail.model.QRCodeByURL;
import org.apache.commons.codec.binary.Base64;
-import org.json.JSONArray;
-import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
@@ -25,11 +27,14 @@ import com.google.api.services.gmail.Gmail;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
+import java.lang.Thread;
+import java.net.ConnectException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
+import java.net.http.HttpTimeoutException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -49,55 +54,82 @@ public class GmailService {
.build();
}
- public JSONObject getEmail(String accessToken) throws IOException, InterruptedException {
- JSONObject json = new JSONObject();
- JSONArray emailArray = new JSONArray();
+ private static final long MAX_RESULTS = 100L;
- // Build the Gmail service
+ public ScannedGmailResponseDto getEmail(String accessToken) throws IOException, InterruptedException {
Gmail service = getGmailService(accessToken);
- logger.info("service-> {}", service);
+ logger.info("Gmail service initialized: {}", service);
- // Get the list of messages
- ListMessagesResponse listResponse = service.users().messages().list("me").execute();
- List messages = listResponse.getMessages();
+ List emailMessagesList = new ArrayList<>();
+ String userId = "me";
+ String nextPageToken = null;
- for (Message message : messages) {
- message = service.users().messages().get("me", message.getId()).setFormat("full").execute();
- List parts = message.getPayload().getParts();
- Set attachmentIds = new HashSet<>();
- Set imageUrls = new HashSet<>();
- processPartsRecursively(parts, attachmentIds, imageUrls);
+ do {
+ ListMessagesResponse listResponse = fetchMessages(service, userId, nextPageToken);
+ List messages = listResponse.getMessages();
+ nextPageToken = listResponse.getNextPageToken();
- // Extract and log the email subject
- String subject = getSubject(message);
- logger.info("Email Subject-> {}", subject);
-
- if (attachmentIds.isEmpty() && imageUrls.isEmpty())
- continue;
-
- String messageId = message.getId();
- logger.info("messageId-> {}", messageId);
- String historyId = String.valueOf(message.getHistoryId());
- logger.info("historyId-> {}", historyId);
-
- for (String attachmentId : attachmentIds) {
- Optional attachment = findAttachmentIdByCid(parts, attachmentId);
- logger.info("attachment-> {}", attachment);
- if (attachment.isPresent()) {
- List qrCodeValue = processAttachment(service, messageId, attachment.get());
- emailArray.put(qrCodeValue);
+ for (Message message : messages) {
+ EmailMessage emailMessage = processMessage(service, userId, message);
+ if (emailMessage != null) {
+ emailMessagesList.add(emailMessage);
}
}
- for (String imageUrl : imageUrls) {
- List qrCodeValue = scanQRCodeFromUrl(imageUrl);
- if (qrCodeValue != null) {
- emailArray.put(qrCodeValue);
+ } while (nextPageToken != null);
+
+ return new ScannedGmailResponseDto(emailMessagesList);
+ }
+
+ private ListMessagesResponse fetchMessages(Gmail service, String userId, String pageToken) throws IOException {
+ return service.users().messages().list(userId)
+ .setPageToken(pageToken)
+ .setMaxResults(MAX_RESULTS)
+ .execute();
+ }
+
+ private EmailMessage processMessage(Gmail service, String userId, Message message) throws IOException, InterruptedException {
+ message = service.users().messages().get(userId, message.getId()).setFormat("full").execute();
+ List parts = message.getPayload().getParts();
+ Set attachmentIds = new HashSet<>();
+ Set imageUrls = new HashSet<>();
+ processPartsRecursively(parts, attachmentIds, imageUrls);
+
+ if (attachmentIds.isEmpty() && imageUrls.isEmpty()) {
+ return null;
+ }
+
+ String subject = getSubject(message);
+ logger.info("Email Subject: {}", subject);
+ logger.info("Message ID: {}", message.getId());
+ logger.info("History ID: {}", message.getHistoryId());
+
+ EmailMessage emailMessage = new EmailMessage(message.getId(), subject, String.valueOf(message.getHistoryId()));
+
+ processAttachments(service, message.getId(), parts, attachmentIds, emailMessage);
+ processImageUrls(imageUrls, emailMessage);
+
+ return emailMessage.hasQRCodes() ? emailMessage : null;
+ }
+
+ private void processAttachments(Gmail service, String messageId, List parts, Set attachmentIds, EmailMessage emailMessage) throws IOException {
+ for (String attachmentId : attachmentIds) {
+ Optional attachment = findAttachmentIdByCid(parts, attachmentId);
+ if (attachment.isPresent()) {
+ List qrCodeValue = processAttachment(service, messageId, attachment.get());
+ if (!qrCodeValue.isEmpty()) {
+ emailMessage.addQRCodeByContentId(new QRCodeByContentId(attachmentId, attachment.get(), qrCodeValue, qrCodeValue.size()));
}
}
}
- logger.info("Total Emails-> {}", messages.size());
- json.put("qr_codes", emailArray);
- return json;
+ }
+
+ private void processImageUrls(Set imageUrls, EmailMessage emailMessage) throws IOException {
+ for (String imageUrl : imageUrls) {
+ List qrCodeValue = scanQRCodeFromUrl(imageUrl);
+ if (!qrCodeValue.isEmpty()) {
+ emailMessage.addQRCodeByURL(new QRCodeByURL(imageUrl, qrCodeValue, qrCodeValue.size()));
+ }
+ }
}
private String getSubject(Message message) {
@@ -140,35 +172,49 @@ public class GmailService {
}
}
}
- private List scanQRCodeFromUrl(String imageUrl) throws IOException, InterruptedException {
+ private List scanQRCodeFromUrl(String imageUrl) {
try {
BufferedImage image = downloadImageFromUrl(imageUrl);
if (image != null) {
return decodeQRCodes(image);
}
+ } catch (IllegalArgumentException e) {
+ logger.error("Invalid URI scheme for URL: {} -> {}", imageUrl, e.getMessage());
} catch(URISyntaxException e) {
logger.error("Error while scanning QR code from URL", e);
}
- return null;
+ return Collections.emptyList();
}
// Download the image from the given URL
- private BufferedImage downloadImageFromUrl(String imageUrl) throws IOException, InterruptedException, URISyntaxException {
- HttpClient client = HttpClient.newBuilder()
- .followRedirects(HttpClient.Redirect.ALWAYS)
- .build();
- logger.info("imageUrl-> {}", imageUrl);
- // Encode the URL
- HttpRequest request = HttpRequest.newBuilder()
- .uri(URI.create(imageUrl.replace(" ", "%20")))
- .GET()
- .build();
+ private BufferedImage downloadImageFromUrl(String imageUrl) throws URISyntaxException {
+ try {
+ imageUrl = imageUrl.replace(" ", "%20");
+ HttpClient client = HttpClient.newBuilder()
+ .followRedirects(HttpClient.Redirect.ALWAYS)
+ .build();
+ logger.info("Downloading image from URL: {}", imageUrl);
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(new URI(imageUrl))
+ .GET()
+ .build();
- HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
- if (response.statusCode() == 200) {
- byte[] imageBytes = response.body();
- return ImageIO.read(new ByteArrayInputStream(imageBytes));
- } else {
- logger.error("Failed to download image. HTTP response code: {}", response.statusCode());
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
+
+ if (response.statusCode() == 200) {
+ byte[] imageBytes = response.body();
+ return ImageIO.read(new ByteArrayInputStream(imageBytes));
+ } else {
+ logger.warn("Failed to download image. HTTP response code: {}", response.statusCode());
+ }
+ } catch (URISyntaxException e) {
+ logger.warn("Invalid URL: {} -> {}", imageUrl, e.getMessage());
+ } catch (HttpTimeoutException e) {
+ logger.warn("Request timed out for URL: {} -> {}", imageUrl, e.getMessage());
+ } catch (ConnectException e) {
+ logger.warn("Failed to connect to URL: {} -> {}", imageUrl, e.getMessage());
+ } catch (IOException | InterruptedException e) {
+ logger.warn("Error downloading image from URL: {} -> {}", imageUrl, e.getMessage());
+ Thread.currentThread().interrupt();
}
return null;
}