blob: aee820966a0864f278576f2eb472bd065a117784 [file] [log] [blame]
// Copyright (C) 2013 The Android Open Source Project
//
// Licensed 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 com.google.gerrit.server.mail;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.CC;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.entities.Account;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.server.ReviewerSet;
import com.google.gerrit.server.account.AccountResolver;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.revwalk.FooterKey;
import org.eclipse.jgit.revwalk.FooterLine;
public class MailUtil {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
public static MailRecipients getRecipientsFromFooters(
AccountResolver accountResolver, List<FooterLine> footerLines)
throws IOException, ConfigInvalidException {
MailRecipients recipients = new MailRecipients();
for (FooterLine footerLine : footerLines) {
try {
if (isReviewer(footerLine)) {
Account.Id accountId = toAccountId(accountResolver, footerLine.getValue().trim());
recipients.reviewers.add(accountId);
logger.atFine().log(
"Added account %d from footer line \"%s\" as reviewer", accountId.get(), footerLine);
} else if (footerLine.matches(FooterKey.CC)) {
Account.Id accountId = toAccountId(accountResolver, footerLine.getValue().trim());
recipients.cc.add(accountId);
logger.atFine().log(
"Added account %d from footer line \"%s\" as cc", accountId.get(), footerLine);
}
} catch (UnprocessableEntityException e) {
logger.atFine().log(
"Skip adding reviewer/cc from footer line \"%s\": %s", footerLine, e.getMessage());
continue;
}
}
return recipients;
}
public static MailRecipients getRecipientsFromReviewers(ReviewerSet reviewers) {
MailRecipients recipients = new MailRecipients();
recipients.reviewers.addAll(reviewers.byState(REVIEWER));
recipients.cc.addAll(reviewers.byState(CC));
return recipients;
}
@SuppressWarnings("deprecation")
private static Account.Id toAccountId(AccountResolver accountResolver, String nameOrEmail)
throws UnprocessableEntityException, IOException, ConfigInvalidException {
return accountResolver.resolveByExactNameOrEmail(nameOrEmail).asUnique().account().id();
}
private static boolean isReviewer(FooterLine candidateFooterLine) {
return candidateFooterLine.matches(FooterKey.SIGNED_OFF_BY)
|| candidateFooterLine.matches(FooterKey.ACKED_BY)
|| candidateFooterLine.matches(FooterConstants.REVIEWED_BY)
|| candidateFooterLine.matches(FooterConstants.TESTED_BY);
}
public static class MailRecipients {
private final Set<Account.Id> reviewers;
private final Set<Account.Id> cc;
public MailRecipients() {
this.reviewers = new HashSet<>();
this.cc = new HashSet<>();
}
public MailRecipients(Set<Account.Id> reviewers, Set<Account.Id> cc) {
this.reviewers = new HashSet<>(reviewers);
this.cc = new HashSet<>(cc);
}
public void add(MailRecipients recipients) {
reviewers.addAll(recipients.reviewers);
cc.addAll(recipients.cc);
}
public void remove(Account.Id toRemove) {
reviewers.remove(toRemove);
cc.remove(toRemove);
}
public Set<Account.Id> getReviewers() {
return Collections.unmodifiableSet(reviewers);
}
public Set<Account.Id> getCcOnly() {
final Set<Account.Id> cc = new HashSet<>(this.cc);
cc.removeAll(reviewers);
return Collections.unmodifiableSet(cc);
}
public Set<Account.Id> getAll() {
final Set<Account.Id> all = new HashSet<>(reviewers.size() + cc.size());
all.addAll(reviewers);
all.addAll(cc);
return Collections.unmodifiableSet(all);
}
}
/** allow wildcard matching for {@code domains} */
public static Pattern glob(String[] domains) {
// if domains is not set, match anything
if (domains == null || domains.length == 0) {
return Pattern.compile(".*");
}
StringBuilder sb = new StringBuilder();
for (String domain : domains) {
String quoted = "\\Q" + domain.replace("\\E", "\\E\\\\E\\Q") + "\\E|";
sb.append(quoted.replace("*", "\\E.*\\Q"));
}
return Pattern.compile(sb.substring(0, sb.length() - 1));
}
}