1 /*
  2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 package org.openjdk.skara.bots.mlbridge;
 24 
 25 import org.openjdk.skara.bot.*;
 26 import org.openjdk.skara.email.EmailAddress;
 27 import org.openjdk.skara.forge.HostedRepository;
 28 import org.openjdk.skara.network.URIBuilder;
 29 import org.openjdk.skara.json.*;
 30 import org.openjdk.skara.mailinglist.MailingListServerFactory;
 31 
 32 import java.nio.file.Path;
 33 import java.time.Duration;
 34 import java.util.*;
 35 import java.util.regex.Pattern;
 36 import java.util.stream.Collectors;
 37 
 38 public class MailingListBridgeBotFactory implements BotFactory {
 39     @Override
 40     public String name() {
 41         return "mlbridge";
 42     }
 43 
 44     @Override
 45     public List<Bot> create(BotConfiguration configuration) {
 46         var ret = new ArrayList<Bot>();
 47         var specific = configuration.specific();
 48 
 49         var from = EmailAddress.from(specific.get("name").asString(), specific.get("mail").asString());
 50         var ignoredUsers = specific.get("ignored").get("users").stream()
 51                                    .map(JSONValue::asString)
 52                                    .collect(Collectors.toSet());
 53         var ignoredComments = specific.get("ignored").get("comments").stream()
 54                                       .map(JSONValue::asString)
 55                                       .map(pattern -> Pattern.compile(pattern, Pattern.MULTILINE | Pattern.DOTALL))
 56                                       .collect(Collectors.toSet());
 57         var listArchive = URIBuilder.base(specific.get("server").get("archive").asString()).build();
 58         var listSmtp = specific.get("server").get("smtp").asString();
 59         var interval = specific.get("server").contains("interval") ? Duration.parse(specific.get("server").get("interval").asString()) : Duration.ofSeconds(1);
 60 
 61         var webrevRepo = configuration.repository(specific.get("webrevs").get("repository").asString());
 62         var webrevRef = configuration.repositoryRef(specific.get("webrevs").get("repository").asString());
 63         var webrevWeb = specific.get("webrevs").get("web").asString();
 64 
 65         var archiveRepo = configuration.repository(specific.get("archive").asString());
 66         var issueTracker = URIBuilder.base(specific.get("issues").asString()).build();
 67 
 68         var allListNames = new HashSet<EmailAddress>();
 69         var allRepositories = new HashSet<HostedRepository>();
 70 
 71         var readyLabels = specific.get("ready").get("labels").stream()
 72                 .map(JSONValue::asString)
 73                 .collect(Collectors.toSet());
 74         var readyComments = specific.get("ready").get("comments").stream()
 75                 .map(JSONValue::asObject)
 76                 .collect(Collectors.toMap(obj -> obj.get("user").asString(),
 77                                           obj -> Pattern.compile(obj.get("pattern").asString())));
 78 
 79         for (var repoConfig : specific.get("repositories").asArray()) {
 80             var repo = repoConfig.get("repository").asString();
 81             var censusRepo = configuration.repository(repoConfig.get("census").asString());
 82             var censusRef = configuration.repositoryRef(repoConfig.get("census").asString());
 83 
 84             Map<String, String> headers = repoConfig.contains("headers") ?
 85                     repoConfig.get("headers").fields().stream()
 86                               .collect(Collectors.toMap(JSONObject.Field::name, field -> field.value().asString())) :
 87                     Map.of();
 88 
 89             var list = EmailAddress.parse(repoConfig.get("list").asString());
 90             var folder = repoConfig.contains("folder") ? repoConfig.get("folder").asString() : configuration.repositoryName(repo);
 91             var bot = new MailingListBridgeBot(from, configuration.repository(repo), archiveRepo,
 92                                                censusRepo, censusRef,
 93                                                list, ignoredUsers, ignoredComments, listArchive, listSmtp,
 94                                                webrevRepo, webrevRef, Path.of(folder),
 95                                                URIBuilder.base(webrevWeb).build(), readyLabels, readyComments,
 96                                                issueTracker, headers, interval);
 97             ret.add(bot);
 98 
 99             allListNames.add(list);
100             allRepositories.add(configuration.repository(repo));
101         }
102 
103         var mailmanServer = MailingListServerFactory.createMailmanServer(listArchive, listSmtp, Duration.ZERO);
104         var allLists = allListNames.stream()
105                                    .map(name -> mailmanServer.getList(name.toString()))
106                                    .collect(Collectors.toSet());
107 
108         var bot = new MailingListArchiveReaderBot(from, allLists, allRepositories);
109         ret.add(bot);
110 
111         return ret;
112     }
113 }