You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2019/04/24 12:32:00 UTC

[sling-org-apache-sling-committer-cli] 31/44: SLING-8368 - Name comparisons fail when accents are missing

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to branch feature/SLING-8337
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-committer-cli.git

commit f884748ff3aafb3868cc63bf01c53984f0723b5d
Author: Radu Cotescu <ra...@apache.org>
AuthorDate: Fri Apr 19 17:46:25 2019 +0200

    SLING-8368 - Name comparisons fail when accents are missing
    
    * made name comparisons ignore accents when looking for a member by name
    * if members use their apache email address for emails, then names will
    automatically be extracted from Whimsy instead of using the name from
    the From/Sender email headers
---
 pom.xml                                            | 10 +++
 .../java/org/apache/sling/cli/impl/mail/Email.java | 88 +++++++++++++++++++---
 .../apache/sling/cli/impl/mail/EmailThread.java    | 31 --------
 .../sling/cli/impl/mail/VoteThreadFinder.java      | 17 ++++-
 .../sling/cli/impl/people/MembersFinder.java       | 17 ++++-
 .../sling/cli/impl/release/TallyVotesCommand.java  | 33 ++++----
 6 files changed, 135 insertions(+), 61 deletions(-)

diff --git a/pom.xml b/pom.xml
index 0fc0dbd..6cdcf27 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,6 +34,16 @@
     <build>
         <plugins>
             <plugin>
+                <artifactId>maven-clean-plugin</artifactId>
+                <configuration>
+                    <filesets>
+                        <fileset>
+                            <directory>launcher</directory>
+                        </fileset>
+                    </filesets>
+                </configuration>
+            </plugin>
+            <plugin>
                 <groupId>biz.aQute.bnd</groupId>
                 <artifactId>bnd-maven-plugin</artifactId>
             </plugin>
diff --git a/src/main/java/org/apache/sling/cli/impl/mail/Email.java b/src/main/java/org/apache/sling/cli/impl/mail/Email.java
index 54ec66e..e11bfaa 100644
--- a/src/main/java/org/apache/sling/cli/impl/mail/Email.java
+++ b/src/main/java/org/apache/sling/cli/impl/mail/Email.java
@@ -16,33 +16,101 @@
  */
 package org.apache.sling.cli.impl.mail;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Properties;
+
+import javax.mail.Address;
+import javax.mail.BodyPart;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+
 public class Email {
-    private String from;
+
+    private String id;
+    private InternetAddress from;
     private String subject;
     private String body;
 
-    public String getFrom() {
-        return from;
+    public Email(String id) {
+        this.id = id;
+        try (CloseableHttpClient client = HttpClients.createDefault()) {
+            URI uri = new URIBuilder("https://lists.apache.org/api/source.lua/" + URLEncoder.encode(id, StandardCharsets.UTF_8)).build();
+            HttpGet get = new HttpGet(uri);
+            try (CloseableHttpResponse response = client.execute(get)) {
+                try (InputStream content = response.getEntity().getContent()) {
+                    if (response.getStatusLine().getStatusCode() != 200) {
+                        throw new IOException("Status line : " + response.getStatusLine());
+                    }
+                    MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()), content);
+                    subject = message.getSubject();
+                    Address[] who = message.getFrom();
+                    if (who.length > 0) {
+                        from = (InternetAddress) who[0];
+                    }
+                    body = getContent(message);
+                }
+            }
+        } catch (URISyntaxException | IOException | MessagingException e) {
+            throw new IllegalArgumentException(e);
+        }
     }
 
-    public void setFrom(String from) {
-        this.from = from;
+    public String getId() {
+        return id;
+    }
+
+    public InternetAddress getFrom() {
+        return from;
     }
 
     public String getSubject() {
         return subject;
     }
 
-    public void setSubject(String subject) {
-        this.subject = subject;
-    }
 
     public String getBody() {
         return body;
     }
 
-    public void setBody(String body) {
-        this.body = body;
+    private String getContent(Message message) throws MessagingException, IOException {
+        String result = "";
+        if (message.isMimeType("text/plain")) {
+            result = message.getContent().toString();
+        } else if (message.isMimeType("multipart/*")) {
+            MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
+            result = getTextFromMimeMultipart(mimeMultipart);
+        }
+        return result;
+    }
+
+    private String getTextFromMimeMultipart(
+            MimeMultipart mimeMultipart) throws MessagingException, IOException {
+        StringBuilder result = new StringBuilder();
+        int count = mimeMultipart.getCount();
+        for (int i = 0; i < count; i++) {
+            BodyPart bodyPart = mimeMultipart.getBodyPart(i);
+            if (bodyPart.isMimeType("text/plain") || bodyPart.isMimeType("text/html")) {
+                result.append("\n").append(bodyPart.getContent());
+            } else if (bodyPart.getContent() instanceof MimeMultipart) {
+                result.append(getTextFromMimeMultipart((MimeMultipart) bodyPart.getContent()));
+            }
+        }
+        return result.toString();
     }
 
 }
diff --git a/src/main/java/org/apache/sling/cli/impl/mail/EmailThread.java b/src/main/java/org/apache/sling/cli/impl/mail/EmailThread.java
deleted file mode 100644
index 03ac673..0000000
--- a/src/main/java/org/apache/sling/cli/impl/mail/EmailThread.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sling.cli.impl.mail;
-
-import java.util.List;
-
-public class EmailThread {
-    private List<Email> emails;
-
-    public List<Email> getEmails() {
-        return emails;
-    }
-
-    public void setEmails(List<Email> emails) {
-        this.emails = emails;
-    }
-}
diff --git a/src/main/java/org/apache/sling/cli/impl/mail/VoteThreadFinder.java b/src/main/java/org/apache/sling/cli/impl/mail/VoteThreadFinder.java
index 0d39968..f48baa1 100644
--- a/src/main/java/org/apache/sling/cli/impl/mail/VoteThreadFinder.java
+++ b/src/main/java/org/apache/sling/cli/impl/mail/VoteThreadFinder.java
@@ -21,6 +21,8 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
@@ -29,12 +31,14 @@ import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.osgi.service.component.annotations.Component;
 
-import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
 
 @Component(service = VoteThreadFinder.class)
 public class VoteThreadFinder {
     
-    public EmailThread findVoteThread(String releaseName) throws IOException {
+    public List<Email> findVoteThread(String releaseName) throws IOException {
         try ( CloseableHttpClient client = HttpClients.createDefault() ) {
             
             URI uri = new URIBuilder("https://lists.apache.org/api/stats.lua")
@@ -50,8 +54,13 @@ public class VoteThreadFinder {
                         InputStreamReader reader = new InputStreamReader(content)) {
                     if ( response.getStatusLine().getStatusCode() != 200 )
                         throw new IOException("Status line : " + response.getStatusLine());
-                    Gson gson = new Gson();
-                    return gson.fromJson(reader, EmailThread.class);
+                    JsonParser parser = new JsonParser();
+                    JsonArray emailsArray = parser.parse(reader).getAsJsonObject().get("emails").getAsJsonArray();
+                    List<Email> emails = new ArrayList<>();
+                    for (JsonElement email : emailsArray) {
+                        emails.add(new Email(email.getAsJsonObject().get("id").getAsString()));
+                    }
+                    return emails;
                 }
             }
         } catch (URISyntaxException e) {
diff --git a/src/main/java/org/apache/sling/cli/impl/people/MembersFinder.java b/src/main/java/org/apache/sling/cli/impl/people/MembersFinder.java
index 70b5469..c26ab9a 100644
--- a/src/main/java/org/apache/sling/cli/impl/people/MembersFinder.java
+++ b/src/main/java/org/apache/sling/cli/impl/people/MembersFinder.java
@@ -21,8 +21,10 @@ package org.apache.sling.cli.impl.people;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.text.Collator;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Locale;
 import java.util.Set;
 
 import org.apache.http.client.methods.CloseableHttpResponse;
@@ -103,7 +105,7 @@ public class MembersFinder {
         return members;
     }
 
-    public Member getMemberById(String id) {
+    public Member findById(String id) {
         for (Member member : findMembers()) {
             if (id.equals(member.getId())) {
                 return member;
@@ -112,8 +114,19 @@ public class MembersFinder {
         return null;
     }
 
+    public Member findByNameOrEmail(String name, String email) {
+        Collator collator = Collator.getInstance(Locale.US);
+        collator.setDecomposition(Collator.NO_DECOMPOSITION);
+        for (Member member : findMembers()) {
+            if (email.equals(member.getEmail()) || collator.compare(name, member.getName()) == 0) {
+                return member;
+            }
+        }
+        return null;
+    }
+
     public Member getCurrentMember() {
-         return getMemberById(credentialsService.getCredentials().getUsername());
+        return findById(credentialsService.getCredentials().getUsername());
     }
 
 }
diff --git a/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java b/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java
index fb3ca95..93dbf0a 100644
--- a/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java
+++ b/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java
@@ -17,14 +17,15 @@
 package org.apache.sling.cli.impl.release;
 
 import java.io.IOException;
+import java.text.Collator;
 import java.util.Arrays;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Locale;
 import java.util.Set;
 import java.util.stream.Collectors;
 
 import org.apache.sling.cli.impl.Command;
 import org.apache.sling.cli.impl.mail.Email;
-import org.apache.sling.cli.impl.mail.EmailThread;
 import org.apache.sling.cli.impl.mail.VoteThreadFinder;
 import org.apache.sling.cli.impl.nexus.StagingRepository;
 import org.apache.sling.cli.impl.nexus.StagingRepositoryFinder;
@@ -84,24 +85,28 @@ public class TallyVotesCommand implements Command {
                     .stream()
                     .map(Release::getFullName)
                     .collect(Collectors.joining(", "));
-            EmailThread voteThread = voteThreadFinder.findVoteThread(releaseName);
 
-            Set<String> bindingVoters = new HashSet<>();
-            Set<String> nonBindingVoters = new HashSet<>();
-            for (Email e : voteThread.getEmails()) {
-                if (isPositiveVote(e)) {
-                    String sender = e.getFrom().replaceAll("<.*>", "").trim();
-                    for (Member m : membersFinder.findMembers()) {
-                        if (sender.equals(m.getName())) {
+            Set<String> bindingVoters = new LinkedHashSet<>();
+            Set<String> nonBindingVoters = new LinkedHashSet<>();
+            Collator collator = Collator.getInstance(Locale.US);
+            collator.setDecomposition(Collator.NO_DECOMPOSITION);
+            voteThreadFinder.findVoteThread(releaseName).stream().skip(1).filter(this::isPositiveVote).forEachOrdered(
+                    email -> {
+                        String from = email.getFrom().getAddress();
+                        String name = email.getFrom().getPersonal();
+                        Member m = membersFinder.findByNameOrEmail(name, from);
+                        if (m != null) {
                             if (m.isPMCMember()) {
-                                bindingVoters.add(sender);
+                                bindingVoters.add(m.getName());
                             } else {
-                                nonBindingVoters.add(sender);
+                                nonBindingVoters.add(m.getName());
                             }
+                        } else {
+                            nonBindingVoters.add(name);
                         }
                     }
-                }
-            }
+            );
+
             String email = EMAIL_TEMPLATE
                 .replace("##RELEASE_NAME##", releaseFullName)
                 .replace("##BINDING_VOTERS##", String.join(", ", bindingVoters))