From a6939fa7f4093e1f5af8369c10ce4cac1b66acd9 Mon Sep 17 00:00:00 2001 From: Blag Date: Tue, 2 Jan 2024 21:18:12 -0500 Subject: [PATCH 1/5] Update README.md --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e422b5b..469cd28 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ This sample will show you to create email threading using Java. You'll need the following values: ```text -ACCESS_TOKEN = "" -CALENDAR_ID = "" +V3_TOKEN_API=API_KEY +GRANT_ID=GRANT_ID ``` Add the above values to a new `.env` file: @@ -34,6 +34,7 @@ spark-core / Spark Java / 2.9.4 spark-template-mustache / Mustache / 2.7.1 jsoup / 1.15.3 spark-template-handlebars / Handlebars / 2.7.1 +org.projectlombok / lombok / 1.18.28 ``` # Compilation @@ -56,6 +57,3 @@ If successful, you will be able to find organized email threads. ## Learn more - -Read the blog post [Grouping Email Threads with Java and Nylas](https://www.nylas.com/blog/grouping-email-threads-with-java-and-nylas-dev/) -Visit our [Nylas Java SDK documentation](https://developer.nylas.com/docs/developer-tools/sdk/java-sdk/) to learn more. From 6a98e72e0992a6bb2aed089d137f42bc66560396 Mon Sep 17 00:00:00 2001 From: Blag Date: Tue, 2 Jan 2024 21:18:36 -0500 Subject: [PATCH 2/5] Update EmailThreading.java --- .../src/main/java/EmailThreading.java | 141 ++++++++++-------- 1 file changed, 81 insertions(+), 60 deletions(-) diff --git a/EmailThreading/src/main/java/EmailThreading.java b/EmailThreading/src/main/java/EmailThreading.java index 54fce3d..5cf4ca4 100644 --- a/EmailThreading/src/main/java/EmailThreading.java +++ b/EmailThreading/src/main/java/EmailThreading.java @@ -1,10 +1,16 @@ // Import Java Utilities import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Path; +import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.*; -import okhttp3.ResponseBody; -import java.nio.file.Paths; + +import com.nylas.models.Thread; +import com.nylas.resources.Contacts; +import com.nylas.resources.Messages; import java.nio.file.Files; // Import Spark and Handlebars libraries @@ -15,43 +21,57 @@ import spark.template.handlebars.HandlebarsTemplateEngine; //Import Nylas Packages -import com.nylas.*; -import com.nylas.Thread; +import com.nylas.NylasClient; +import com.nylas.models.*; //Import DotEnv to handle .env files import io.github.cdimascio.dotenv.Dotenv; public class EmailThreading { - static RemoteCollection get_contact(Contacts _contact, String email) throws RequestFailedException, IOException { - RemoteCollection contact_list = _contact.list(new ContactQuery().email(email)); - return contact_list; + static ListResponse get_contact(String grant_id, NylasClient nylas, String email) throws NylasSdkTimeoutError, NylasApiError { + ListContactsQueryParams query_params = new ListContactsQueryParams. + Builder(). + email(email). + build(); + return nylas.contacts().list(grant_id, query_params); } - static void download_contact_picture(NylasAccount account, String id) throws RequestFailedException, IOException{ - try (ResponseBody picResponse = account.contacts().downloadProfilePicture(id)) { - Files.copy(picResponse.byteStream(), Paths.get("src/main/resources/public/images/" + id +".png")); - }catch (Exception e){ - System.out.println("Image was already downloaded"); + static void download_contact_picture(String grant_id, NylasClient nylas, String id) throws NylasSdkTimeoutError, NylasApiError{ + Contact contact = nylas.contacts().find(grant_id, id).getData(); + String img = "src/main/resources/public/images/" + contact.getGivenName() + "_" + contact.getSurname() + ".png"; + try { + assert contact.getPictureUrl() != null; + Path target = Path.of(img); + Files.deleteIfExists(target); + try(InputStream in = new URL(contact.getPictureUrl()).openStream()){ + Files.copy(in, target); + } + } catch (IOException e) { + throw new RuntimeException(e); } } - public static void main(String[] args) { + public static void main(String[] args) throws + NylasSdkTimeoutError, NylasApiError + { + main_thread mainThread = new main_thread(); + ArrayList data_threads = new ArrayList<>(); + ArrayList> all_threads = new ArrayList<>(); + staticFiles.location("/public"); // Load the .env file Dotenv dotenv = Dotenv.load(); - // Create the client object - NylasClient client = new NylasClient(); // Connect it to Nylas using the Access Token from the .env file - NylasAccount account = client.account(dotenv.get("ACCESS_TOKEN")); + NylasClient nylas = new NylasClient.Builder(dotenv.get("V3_TOKEN_API")).build(); // Get access to messages - Messages messages = account.messages(); + Messages messages = nylas.messages(); // Get access to contacts - Contacts contacts = account.contacts(); + Contacts contacts = nylas.contacts(); // Default path when we load our web application // Hashmap to send parameters to our handlebars view - Map map = new HashMap(); + Map map = new HashMap(); map.put("search", ""); get("/", (request, response) -> @@ -62,13 +82,18 @@ public static void main(String[] args) { // When we submit the form, we're posting data post("/", (request, response) -> { + all_threads.clear(); // Get parameter from form String search = request.queryParams("search"); // Search all threads related to the email address - Threads threads = account.threads(); - List thread = threads.list(new ThreadQuery(). - in("inbox").from(search)).fetchAll(); - if (search.equals("")) { + + ListThreadsQueryParams queryParams = new ListThreadsQueryParams.Builder(). + searchQueryNative("from: " + search). + build(); + + ListResponse thread = nylas.threads().list(dotenv.get("GRANT_ID"), queryParams); + + if (search.isEmpty()) { String halt_msg = "\n" + "\n" + " \n" + @@ -83,37 +108,32 @@ public static void main(String[] args) { halt(halt_msg); } - // This ArrayList will hold all the threads with their - // accompanying information - ArrayList>> _threads = new ArrayList>>(); + String body = ""; + String names = ""; + String pictures = ""; // Look for threads with more than 1 message - for (Thread msg_thread : thread) { - // Auxiliary variables - ArrayList> _thread = new ArrayList>(); - ArrayList _messages = new ArrayList(); - ArrayList aux_messages = new ArrayList(); - ArrayList _pictures = new ArrayList(); - ArrayList _names = new ArrayList(); + for (Thread msg_thread : thread.getData()) { // Only add threads with two messages or more + assert msg_thread.getMessageIds() != null; if (msg_thread.getMessageIds().size() > 1) { // Get the subject of the first email - aux_messages.add(msg_thread.getSubject()); - _thread.add(aux_messages); + String subject = msg_thread.getSubject(); // Loop through all messages contained in the thread for (String message_ids : msg_thread.getMessageIds()) { // Get information from the message - Message message = messages.get(message_ids); + Response message = nylas.messages().find(dotenv.get("GRANT_ID"), message_ids); // Try to get the contact information - RemoteCollection contact = get_contact(contacts, message.getFrom().get(0).getEmail()); - if (contact != null && !contact.fetchAll().get(0).getId().isEmpty()) { + ListResponse contact = get_contact(dotenv.get("GRANT_ID"), nylas, message.getData().getFrom().get(0).getEmail()); + if (!contact.getData().get(0).getId().isEmpty()) { // If the contact is available, downloads its profile picture - download_contact_picture(account, contact.fetchAll().get(0).getId()); + download_contact_picture(dotenv.get("GRANT_ID"), nylas, contact.getData().get(0).getId()); } // Remove extra information from the message, like appended // message, email and phone number - String parsed_message = message.getBody(); + String parsed_message = message.getData().getBody(); + assert parsed_message != null; parsed_message = parsed_message.replaceAll("\\\\n", "\n\n"); parsed_message = Jsoup.clean(parsed_message, Safelist.basic()); // Phone number @@ -126,42 +146,43 @@ public static void main(String[] args) { pattern_key = "(?s)(\\bOn.*\\b)(?!.*\\1).+"; parsed_message = parsed_message.replaceAll(pattern_key, ""); // Twitter handler - pattern_key = "(?i)twitter:.+"; + pattern_key = "(?i)twitter:.+"; parsed_message = parsed_message.replaceAll(pattern_key, ""); - _messages.add(parsed_message); + body = parsed_message; // Convert date to something readable - LocalDateTime ldt = LocalDateTime.ofInstant(message.getDate(), ZoneOffset.UTC); + LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochSecond(message.getData().getDate()), ZoneOffset.UTC); String date = ldt.getYear() + "-" + ldt.getMonthValue() + "-" + ldt.getDayOfMonth(); String time = ldt.getHour() + ":" + ldt.getMinute() + ":" + ldt.getSecond(); // If there's no contact - if (contact == null || contact.fetchAll().get(0).getId().isEmpty()) { - _pictures.add("NotFound.png"); - _names.add("Not Found" + " on" + date + " at " + time); + if (contact.getData().get(0).getId().isEmpty()) { + pictures = "NotFound.png"; + names = "Not Found" + " on" + date + " at " + time; } else { // If there's a contact, pass picture information, // name and date and time of message - _pictures.add(contact.fetchAll().get(0).getId() + ".png"); - _names.add(contact.fetchAll().get(0).getGivenName() + " " + - contact.fetchAll().get(0).getSurname() + " on " + - date + " at " + time); + pictures = contact.getData().get(0).getGivenName() + "_" + contact.getData().get(0).getSurname() + ".png"; + names = contact.getData().get(0).getGivenName() + " " + + contact.getData().get(0).getGivenName() + " on " + + date + " at " + time; } - + main_thread new_mainThread = new main_thread(); + new_mainThread.setThread(subject); + new_mainThread.setMessage(body); + new_mainThread.setNames(names); + new_mainThread.setPicture(pictures); + data_threads.add(new_mainThread); } - // Add ArrayLists to main thread arraylist - // and then add them all - _thread.add(_messages); - _thread.add(_pictures); - _thread.add(_names); - _threads.add(_thread); + all_threads.add(new ArrayList<>(data_threads)); + data_threads.clear(); } } // Hashmap to send parameters to our handlebars view - Map thread_map = new HashMap(); + Map>> thread_map = new HashMap>>(); // We're passing the same _threads ArrayList twice // as we need the copy for processing - thread_map.put("threads", _threads); - thread_map.put("inner_threads", _threads); + thread_map.put("threads", all_threads); + thread_map.put("inner_threads", all_threads); // Call the handlebars template return new ModelAndView(thread_map, "main.hbs"); From 131001775cd0ffddafb605c21e5c08849e76c014 Mon Sep 17 00:00:00 2001 From: Blag Date: Tue, 2 Jan 2024 21:19:02 -0500 Subject: [PATCH 3/5] Create main_thread.java --- EmailThreading/src/main/java/main_thread.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 EmailThreading/src/main/java/main_thread.java diff --git a/EmailThreading/src/main/java/main_thread.java b/EmailThreading/src/main/java/main_thread.java new file mode 100644 index 0000000..5377502 --- /dev/null +++ b/EmailThreading/src/main/java/main_thread.java @@ -0,0 +1,9 @@ +import lombok.Data; + +@Data +public class main_thread { + private String thread; + private String message; + private String picture; + private String names; +} From 2124e2f45ed013ccce65df104995a1627bf130fa Mon Sep 17 00:00:00 2001 From: Blag Date: Tue, 2 Jan 2024 21:19:14 -0500 Subject: [PATCH 4/5] Update pom.xml --- EmailThreading/pom.xml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/EmailThreading/pom.xml b/EmailThreading/pom.xml index b0fe468..98b48a8 100644 --- a/EmailThreading/pom.xml +++ b/EmailThreading/pom.xml @@ -5,13 +5,13 @@ 4.0.0 EmailThreading - EmailThreading + Java_EmailThreading_v3 1.0-SNAPSHOT UTF-8 - 17 - 17 + 18 + 18 @@ -25,6 +25,11 @@ spark-core 2.9.4 + + org.projectlombok + lombok + 1.18.28 + com.sparkjava spark-template-mustache @@ -33,12 +38,12 @@ io.github.cdimascio dotenv-java - 2.2.4 + 2.3.1 - com.nylas.sdk - nylas-java-sdk - 1.18.0 + com.nylas.java + nylas_java + 2.0.0 From aea8e2f551a0e120d6eccd289141ba3a2114cb51 Mon Sep 17 00:00:00 2001 From: Blag Date: Tue, 2 Jan 2024 21:19:34 -0500 Subject: [PATCH 5/5] Update main.hbs --- .../src/main/resources/templates/main.hbs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/EmailThreading/src/main/resources/templates/main.hbs b/EmailThreading/src/main/resources/templates/main.hbs index 72e2287..4454f4c 100644 --- a/EmailThreading/src/main/resources/templates/main.hbs +++ b/EmailThreading/src/main/resources/templates/main.hbs @@ -11,7 +11,9 @@
-    +   
@@ -27,7 +29,7 @@ data-accordion-target="#accordion-collapse-body-{{@index}}" aria-expanded="false" aria-controls="accordion-collapse-body-{{@index}}"> - {{this.[0].[0]}} + {{this.[0].thread}}