Initial completion of scanning of qr code from gmail
This commit is contained in:
12
pom.xml
12
pom.xml
@@ -109,6 +109,18 @@
|
|||||||
<artifactId>jsoup</artifactId>
|
<artifactId>jsoup</artifactId>
|
||||||
<version>1.18.1</version>
|
<version>1.18.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.17.2</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-annotations</artifactId>
|
||||||
|
<version>2.17.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.safeqr.app.gmail.controller;
|
package com.safeqr.app.gmail.controller;
|
||||||
|
|
||||||
import com.google.api.services.gmail.model.*;
|
import com.google.api.services.gmail.model.*;
|
||||||
|
import com.safeqr.app.gmail.dto.ScannedGmailResponseDto;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import com.google.api.client.auth.oauth2.AuthorizationCodeRequestUrl;
|
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<>("Access token is missing", HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ResponseEntity<>(gmailService.getEmail(accessToken).toString(), HttpStatus.OK);
|
return new ResponseEntity<>(gmailService.getEmail(accessToken), HttpStatus.OK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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<EmailMessage> messages;
|
||||||
|
}
|
||||||
38
src/main/java/com/safeqr/app/gmail/model/EmailMessage.java
Normal file
38
src/main/java/com/safeqr/app/gmail/model/EmailMessage.java
Normal file
@@ -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> qrCodeByContentId;
|
||||||
|
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
|
List<QRCodeByURL> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<String> decodedContent;
|
||||||
|
private int totalQRCodeFound;
|
||||||
|
}
|
||||||
17
src/main/java/com/safeqr/app/gmail/model/QRCodeByURL.java
Normal file
17
src/main/java/com/safeqr/app/gmail/model/QRCodeByURL.java
Normal file
@@ -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<String> decodedContent;
|
||||||
|
private int totalQRCodeFound;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,9 +7,11 @@ import com.google.zxing.*;
|
|||||||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
||||||
import com.google.zxing.common.HybridBinarizer;
|
import com.google.zxing.common.HybridBinarizer;
|
||||||
import com.google.zxing.multi.qrcode.QRCodeMultiReader;
|
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.apache.commons.codec.binary.Base64;
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
import org.jsoup.nodes.Document;
|
import org.jsoup.nodes.Document;
|
||||||
import org.jsoup.select.Elements;
|
import org.jsoup.select.Elements;
|
||||||
@@ -25,11 +27,14 @@ import com.google.api.services.gmail.Gmail;
|
|||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.lang.Thread;
|
||||||
|
import java.net.ConnectException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
import java.net.http.HttpRequest;
|
import java.net.http.HttpRequest;
|
||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
|
import java.net.http.HttpTimeoutException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@@ -49,56 +54,83 @@ public class GmailService {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject getEmail(String accessToken) throws IOException, InterruptedException {
|
private static final long MAX_RESULTS = 100L;
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
JSONArray emailArray = new JSONArray();
|
|
||||||
|
|
||||||
// Build the Gmail service
|
public ScannedGmailResponseDto getEmail(String accessToken) throws IOException, InterruptedException {
|
||||||
Gmail service = getGmailService(accessToken);
|
Gmail service = getGmailService(accessToken);
|
||||||
logger.info("service-> {}", service);
|
logger.info("Gmail service initialized: {}", service);
|
||||||
|
|
||||||
// Get the list of messages
|
List<EmailMessage> emailMessagesList = new ArrayList<>();
|
||||||
ListMessagesResponse listResponse = service.users().messages().list("me").execute();
|
String userId = "me";
|
||||||
|
String nextPageToken = null;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ListMessagesResponse listResponse = fetchMessages(service, userId, nextPageToken);
|
||||||
List<Message> messages = listResponse.getMessages();
|
List<Message> messages = listResponse.getMessages();
|
||||||
|
nextPageToken = listResponse.getNextPageToken();
|
||||||
|
|
||||||
for (Message message : messages) {
|
for (Message message : messages) {
|
||||||
message = service.users().messages().get("me", message.getId()).setFormat("full").execute();
|
EmailMessage emailMessage = processMessage(service, userId, message);
|
||||||
|
if (emailMessage != null) {
|
||||||
|
emailMessagesList.add(emailMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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<MessagePart> parts = message.getPayload().getParts();
|
List<MessagePart> parts = message.getPayload().getParts();
|
||||||
Set<String> attachmentIds = new HashSet<>();
|
Set<String> attachmentIds = new HashSet<>();
|
||||||
Set<String> imageUrls = new HashSet<>();
|
Set<String> imageUrls = new HashSet<>();
|
||||||
processPartsRecursively(parts, attachmentIds, imageUrls);
|
processPartsRecursively(parts, attachmentIds, imageUrls);
|
||||||
|
|
||||||
// Extract and log the email subject
|
if (attachmentIds.isEmpty() && imageUrls.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String subject = getSubject(message);
|
String subject = getSubject(message);
|
||||||
logger.info("Email Subject-> {}", subject);
|
logger.info("Email Subject: {}", subject);
|
||||||
|
logger.info("Message ID: {}", message.getId());
|
||||||
|
logger.info("History ID: {}", message.getHistoryId());
|
||||||
|
|
||||||
if (attachmentIds.isEmpty() && imageUrls.isEmpty())
|
EmailMessage emailMessage = new EmailMessage(message.getId(), subject, String.valueOf(message.getHistoryId()));
|
||||||
continue;
|
|
||||||
|
|
||||||
String messageId = message.getId();
|
processAttachments(service, message.getId(), parts, attachmentIds, emailMessage);
|
||||||
logger.info("messageId-> {}", messageId);
|
processImageUrls(imageUrls, emailMessage);
|
||||||
String historyId = String.valueOf(message.getHistoryId());
|
|
||||||
logger.info("historyId-> {}", historyId);
|
|
||||||
|
|
||||||
|
return emailMessage.hasQRCodes() ? emailMessage : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processAttachments(Gmail service, String messageId, List<MessagePart> parts, Set<String> attachmentIds, EmailMessage emailMessage) throws IOException {
|
||||||
for (String attachmentId : attachmentIds) {
|
for (String attachmentId : attachmentIds) {
|
||||||
Optional<String> attachment = findAttachmentIdByCid(parts, attachmentId);
|
Optional<String> attachment = findAttachmentIdByCid(parts, attachmentId);
|
||||||
logger.info("attachment-> {}", attachment);
|
|
||||||
if (attachment.isPresent()) {
|
if (attachment.isPresent()) {
|
||||||
List<String> qrCodeValue = processAttachment(service, messageId, attachment.get());
|
List<String> qrCodeValue = processAttachment(service, messageId, attachment.get());
|
||||||
emailArray.put(qrCodeValue);
|
if (!qrCodeValue.isEmpty()) {
|
||||||
|
emailMessage.addQRCodeByContentId(new QRCodeByContentId(attachmentId, attachment.get(), qrCodeValue, qrCodeValue.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processImageUrls(Set<String> imageUrls, EmailMessage emailMessage) throws IOException {
|
||||||
for (String imageUrl : imageUrls) {
|
for (String imageUrl : imageUrls) {
|
||||||
List<String> qrCodeValue = scanQRCodeFromUrl(imageUrl);
|
List<String> qrCodeValue = scanQRCodeFromUrl(imageUrl);
|
||||||
if (qrCodeValue != null) {
|
if (!qrCodeValue.isEmpty()) {
|
||||||
emailArray.put(qrCodeValue);
|
emailMessage.addQRCodeByURL(new QRCodeByURL(imageUrl, qrCodeValue, qrCodeValue.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info("Total Emails-> {}", messages.size());
|
|
||||||
json.put("qr_codes", emailArray);
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getSubject(Message message) {
|
private String getSubject(Message message) {
|
||||||
return message.getPayload().getHeaders().stream()
|
return message.getPayload().getHeaders().stream()
|
||||||
@@ -140,35 +172,49 @@ public class GmailService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private List<String> scanQRCodeFromUrl(String imageUrl) throws IOException, InterruptedException {
|
private List<String> scanQRCodeFromUrl(String imageUrl) {
|
||||||
try {
|
try {
|
||||||
BufferedImage image = downloadImageFromUrl(imageUrl);
|
BufferedImage image = downloadImageFromUrl(imageUrl);
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
return decodeQRCodes(image);
|
return decodeQRCodes(image);
|
||||||
}
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
logger.error("Invalid URI scheme for URL: {} -> {}", imageUrl, e.getMessage());
|
||||||
} catch(URISyntaxException e) {
|
} catch(URISyntaxException e) {
|
||||||
logger.error("Error while scanning QR code from URL", e);
|
logger.error("Error while scanning QR code from URL", e);
|
||||||
}
|
}
|
||||||
return null;
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
// Download the image from the given URL
|
// Download the image from the given URL
|
||||||
private BufferedImage downloadImageFromUrl(String imageUrl) throws IOException, InterruptedException, URISyntaxException {
|
private BufferedImage downloadImageFromUrl(String imageUrl) throws URISyntaxException {
|
||||||
|
try {
|
||||||
|
imageUrl = imageUrl.replace(" ", "%20");
|
||||||
HttpClient client = HttpClient.newBuilder()
|
HttpClient client = HttpClient.newBuilder()
|
||||||
.followRedirects(HttpClient.Redirect.ALWAYS)
|
.followRedirects(HttpClient.Redirect.ALWAYS)
|
||||||
.build();
|
.build();
|
||||||
logger.info("imageUrl-> {}", imageUrl);
|
logger.info("Downloading image from URL: {}", imageUrl);
|
||||||
// Encode the URL
|
|
||||||
HttpRequest request = HttpRequest.newBuilder()
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
.uri(URI.create(imageUrl.replace(" ", "%20")))
|
.uri(new URI(imageUrl))
|
||||||
.GET()
|
.GET()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||||
|
|
||||||
if (response.statusCode() == 200) {
|
if (response.statusCode() == 200) {
|
||||||
byte[] imageBytes = response.body();
|
byte[] imageBytes = response.body();
|
||||||
return ImageIO.read(new ByteArrayInputStream(imageBytes));
|
return ImageIO.read(new ByteArrayInputStream(imageBytes));
|
||||||
} else {
|
} else {
|
||||||
logger.error("Failed to download image. HTTP response code: {}", response.statusCode());
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user