Commit 873ea6bb by lepdou

refactor email builder

parent f144fe06
package com.ctrip.framework.apollo.portal.components.emailbuilder; package com.ctrip.framework.apollo.portal.components.emailbuilder;
import com.google.common.collect.Lists;
import com.ctrip.framework.apollo.common.constants.ReleaseOperation; import com.ctrip.framework.apollo.common.constants.ReleaseOperation;
import com.ctrip.framework.apollo.common.dto.ReleaseDTO; import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
import com.ctrip.framework.apollo.common.entity.AppNamespace; import com.ctrip.framework.apollo.common.entity.AppNamespace;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.core.enums.Env; import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.constant.RoleType; import com.ctrip.framework.apollo.portal.constant.RoleType;
...@@ -16,15 +19,20 @@ import com.ctrip.framework.apollo.portal.service.AppNamespaceService; ...@@ -16,15 +19,20 @@ import com.ctrip.framework.apollo.portal.service.AppNamespaceService;
import com.ctrip.framework.apollo.portal.service.ReleaseService; import com.ctrip.framework.apollo.portal.service.ReleaseService;
import com.ctrip.framework.apollo.portal.service.RolePermissionService; import com.ctrip.framework.apollo.portal.service.RolePermissionService;
import com.ctrip.framework.apollo.portal.service.ServerConfigService; import com.ctrip.framework.apollo.portal.service.ServerConfigService;
import com.ctrip.framework.apollo.portal.spi.UserService;
import com.ctrip.framework.apollo.portal.util.RoleUtils; import com.ctrip.framework.apollo.portal.util.RoleUtils;
import org.apache.commons.lang.time.FastDateFormat; import org.apache.commons.lang.time.FastDateFormat;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
...@@ -62,7 +70,6 @@ public abstract class ConfigPublishEmailBuilder { ...@@ -62,7 +70,6 @@ public abstract class ConfigPublishEmailBuilder {
private FastDateFormat dateFormat = FastDateFormat.getInstance("yyyy-MM-dd hh:mm:ss"); private FastDateFormat dateFormat = FastDateFormat.getInstance("yyyy-MM-dd hh:mm:ss");
private String emailAddressSuffix;
private String emailSender; private String emailSender;
@Autowired @Autowired
...@@ -73,10 +80,11 @@ public abstract class ConfigPublishEmailBuilder { ...@@ -73,10 +80,11 @@ public abstract class ConfigPublishEmailBuilder {
private ReleaseService releaseService; private ReleaseService releaseService;
@Autowired @Autowired
private AppNamespaceService appNamespaceService; private AppNamespaceService appNamespaceService;
@Autowired
private UserService userService;
@PostConstruct @PostConstruct
public void init() { public void init() {
emailAddressSuffix = serverConfigService.getValue("email.address.suffix");
emailSender = serverConfigService.getValue("email.sender"); emailSender = serverConfigService.getValue("email.sender");
} }
...@@ -103,15 +111,31 @@ public abstract class ConfigPublishEmailBuilder { ...@@ -103,15 +111,31 @@ public abstract class ConfigPublishEmailBuilder {
Set<UserInfo> releaseRoleUsers = Set<UserInfo> releaseRoleUsers =
rolePermissionService rolePermissionService
.queryUsersWithRole(RoleUtils.buildNamespaceRoleName(appId, namespaceName, RoleType.RELEASE_NAMESPACE)); .queryUsersWithRole(RoleUtils.buildNamespaceRoleName(appId, namespaceName, RoleType.RELEASE_NAMESPACE));
Set<UserInfo> owners = rolePermissionService.queryUsersWithRole(RoleUtils.buildAppMasterRoleName(appId));
List<String> recipients = new ArrayList<>(modifyRoleUsers.size() + releaseRoleUsers.size()); Set<String> userIds = new HashSet<>(modifyRoleUsers.size() + releaseRoleUsers.size() + owners.size());
for (UserInfo userInfo : modifyRoleUsers) { for (UserInfo userInfo : modifyRoleUsers) {
recipients.add(userInfo.getUserId() + emailAddressSuffix); userIds.add(userInfo.getUserId());
} }
for (UserInfo userInfo : releaseRoleUsers) { for (UserInfo userInfo : releaseRoleUsers) {
recipients.add(userInfo.getUserId() + emailAddressSuffix); userIds.add(userInfo.getUserId());
}
for (UserInfo userInfo : owners) {
userIds.add(userInfo.getUserId());
}
List<UserInfo> userInfos = userService.findByUserIds(Lists.newArrayList(userIds));
if (CollectionUtils.isEmpty(userInfos)){
return Collections.emptyList();
}
List<String> recipients = new ArrayList<>(userInfos.size());
for (UserInfo userInfo: userInfos){
recipients.add(userInfo.getEmail());
} }
return recipients; return recipients;
...@@ -124,15 +148,15 @@ public abstract class ConfigPublishEmailBuilder { ...@@ -124,15 +148,15 @@ public abstract class ConfigPublishEmailBuilder {
} }
private String renderReleaseBasicInfo(String template, Env env, ReleaseHistoryBO releaseHistory) { private String renderReleaseBasicInfo(String template, Env env, ReleaseHistoryBO releaseHistory) {
String renderResult = template.replaceAll(EMAIL_CONTENT_FIELD_APPID, releaseHistory.getAppId()); String renderResult = template.replaceAll(EMAIL_CONTENT_FIELD_APPID, Matcher.quoteReplacement(releaseHistory.getAppId()));
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_ENV, env.toString()); renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_ENV, Matcher.quoteReplacement(env.toString()));
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_CLUSTER, releaseHistory.getClusterName()); renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_CLUSTER, Matcher.quoteReplacement(releaseHistory.getClusterName()));
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_NAMESPACE, releaseHistory.getNamespaceName()); renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_NAMESPACE, Matcher.quoteReplacement(releaseHistory.getNamespaceName()));
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_OPERATOR, releaseHistory.getOperator()); renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_OPERATOR, Matcher.quoteReplacement(releaseHistory.getOperator()));
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_RELEASE_TITLE, releaseHistory.getReleaseTitle()); renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_RELEASE_TITLE, Matcher.quoteReplacement(releaseHistory.getReleaseTitle()));
renderResult = renderResult =
renderResult.replaceAll(EMAIL_CONTENT_FIELD_RELEASE_ID, String.valueOf(releaseHistory.getReleaseId())); renderResult.replaceAll(EMAIL_CONTENT_FIELD_RELEASE_ID, String.valueOf(releaseHistory.getReleaseId()));
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_RELEASE_COMMENT, releaseHistory.getReleaseComment()); renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_RELEASE_COMMENT, Matcher.quoteReplacement(releaseHistory.getReleaseComment()));
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_APOLLO_SERVER_ADDRESS, getApolloPortalAddress()); renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_APOLLO_SERVER_ADDRESS, getApolloPortalAddress());
return renderResult return renderResult
.replaceAll(EMAIL_CONTENT_FIELD_RELEASE_TIME, dateFormat.format(releaseHistory.getReleaseTime())); .replaceAll(EMAIL_CONTENT_FIELD_RELEASE_TIME, dateFormat.format(releaseHistory.getReleaseTime()));
...@@ -150,7 +174,8 @@ public abstract class ConfigPublishEmailBuilder { ...@@ -150,7 +174,8 @@ public abstract class ConfigPublishEmailBuilder {
//don't show diff content if namespace's format is file //don't show diff content if namespace's format is file
if (appNamespace == null || if (appNamespace == null ||
!appNamespace.getFormat().equals(ConfigFileFormat.Properties.getValue())) { !appNamespace.getFormat().equals(ConfigFileFormat.Properties.getValue())) {
return template;
return template.replaceAll(EMAIL_CONTENT_FIELD_DIFF, "请点击链接到Apollo上查看");
} }
ReleaseCompareResult result = getReleaseCompareResult(env, releaseHistory); ReleaseCompareResult result = getReleaseCompareResult(env, releaseHistory);
...@@ -177,7 +202,8 @@ public abstract class ConfigPublishEmailBuilder { ...@@ -177,7 +202,8 @@ public abstract class ConfigPublishEmailBuilder {
changesHtmlBuilder.append("</tr>"); changesHtmlBuilder.append("</tr>");
} }
String renderResult = template.replaceAll(EMAIL_CONTENT_FIELD_DIFF, changesHtmlBuilder.toString()); String diffContent = Matcher.quoteReplacement(changesHtmlBuilder.toString());
String renderResult = template.replaceAll(EMAIL_CONTENT_FIELD_DIFF, diffContent);
return renderResult.replaceAll(EMAIL_CONTENT_DIFF_HAS_CONTENT_SWITCH, ""); return renderResult.replaceAll(EMAIL_CONTENT_DIFF_HAS_CONTENT_SWITCH, "");
} }
...@@ -214,5 +240,4 @@ public abstract class ConfigPublishEmailBuilder { ...@@ -214,5 +240,4 @@ public abstract class ConfigPublishEmailBuilder {
return source; return source;
} }
} }
...@@ -13,6 +13,7 @@ import org.springframework.util.CollectionUtils; ...@@ -13,6 +13,7 @@ import org.springframework.util.CollectionUtils;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher;
@Component @Component
public class GrayPublishEmailBuilder extends ConfigPublishEmailBuilder { public class GrayPublishEmailBuilder extends ConfigPublishEmailBuilder {
...@@ -59,7 +60,7 @@ public class GrayPublishEmailBuilder extends ConfigPublishEmailBuilder { ...@@ -59,7 +60,7 @@ public class GrayPublishEmailBuilder extends ConfigPublishEmailBuilder {
} }
} }
return result.replaceAll(EMAIL_CONTENT_FIELD_RULE, rulesHtmlBuilder.toString()); return result.replaceAll(EMAIL_CONTENT_FIELD_RULE, Matcher.quoteReplacement(rulesHtmlBuilder.toString()));
} }
} }
...@@ -13,6 +13,8 @@ import com.ctrip.framework.apollo.portal.service.ServerConfigService; ...@@ -13,6 +13,8 @@ import com.ctrip.framework.apollo.portal.service.ServerConfigService;
import com.ctrip.framework.apollo.portal.spi.EmailService; import com.ctrip.framework.apollo.portal.spi.EmailService;
import com.ctrip.framework.apollo.tracer.Tracer; import com.ctrip.framework.apollo.tracer.Tracer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -24,6 +26,7 @@ import javax.annotation.PostConstruct; ...@@ -24,6 +26,7 @@ import javax.annotation.PostConstruct;
@Component @Component
public class ConfigPublishListener { public class ConfigPublishListener {
private static final Logger logger = LoggerFactory.getLogger(ConfigPublishListener.class);
@Autowired @Autowired
private ServerConfigService serverConfigService; private ServerConfigService serverConfigService;
...@@ -53,6 +56,7 @@ public class ConfigPublishListener { ...@@ -53,6 +56,7 @@ public class ConfigPublishListener {
emailSupportedEnvs.add(Env.fromString(env.trim())); emailSupportedEnvs.add(Env.fromString(env.trim()));
} }
} catch (Exception e) { } catch (Exception e) {
logger.error("init email supported envs failed.", e);
Tracer.logError("init email supported envs failed.", e); Tracer.logError("init email supported envs failed.", e);
} }
...@@ -75,12 +79,16 @@ public class ConfigPublishListener { ...@@ -75,12 +79,16 @@ public class ConfigPublishListener {
int realOperation = releaseHistory.getOperation(); int realOperation = releaseHistory.getOperation();
Email email = buildEmail(env, releaseHistory, realOperation); Email email = null;
try {
email = buildEmail(env, releaseHistory, realOperation);
} catch (Throwable e) {
Tracer.logError("build email failed.", e);
}
if (email != null) { if (email != null) {
emailService.send(email); emailService.send(email);
} }
} }
private ReleaseHistoryBO getReleaseHistory(ConfigPublishEvent event) { private ReleaseHistoryBO getReleaseHistory(ConfigPublishEvent event) {
...@@ -99,7 +107,7 @@ public class ConfigPublishListener { ...@@ -99,7 +107,7 @@ public class ConfigPublishListener {
if (info.isRollbackEvent()) { if (info.isRollbackEvent()) {
return releaseHistoryService return releaseHistoryService
.findLatestByPreviousReleaseIdAndOperation(env, info.getPreviousReleaseId(), operation); .findLatestByPreviousReleaseIdAndOperation(env, info.getPreviousReleaseId(), operation);
}else { } else {
return releaseHistoryService.findLatestByReleaseIdAndOperation(env, info.getReleaseId(), operation); return releaseHistoryService.findLatestByReleaseIdAndOperation(env, info.getReleaseId(), operation);
} }
......
...@@ -3,6 +3,7 @@ package com.ctrip.framework.apollo.portal.spi; ...@@ -3,6 +3,7 @@ package com.ctrip.framework.apollo.portal.spi;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
...@@ -13,4 +14,5 @@ public interface UserService { ...@@ -13,4 +14,5 @@ public interface UserService {
UserInfo findByUserId(String userId); UserInfo findByUserId(String userId);
List<UserInfo> findByUserIds(List<String> userIds); List<UserInfo> findByUserIds(List<String> userIds);
} }
...@@ -18,8 +18,10 @@ import org.springframework.util.CollectionUtils; ...@@ -18,8 +18,10 @@ import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
...@@ -31,6 +33,7 @@ public class CtripUserService implements UserService { ...@@ -31,6 +33,7 @@ public class CtripUserService implements UserService {
private List<String> searchUserMatchFields; private List<String> searchUserMatchFields;
private ParameterizedTypeReference<Map<String, List<UserServiceResponse>>> responseType; private ParameterizedTypeReference<Map<String, List<UserServiceResponse>>> responseType;
public CtripUserService(ServerConfigService serverConfigService) { public CtripUserService(ServerConfigService serverConfigService) {
this.serverConfigService = serverConfigService; this.serverConfigService = serverConfigService;
this.restTemplate = new RestTemplate(clientHttpRequestFactory()); this.restTemplate = new RestTemplate(clientHttpRequestFactory());
......
...@@ -5,8 +5,13 @@ import com.google.common.collect.Lists; ...@@ -5,8 +5,13 @@ import com.google.common.collect.Lists;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.spi.UserService; import com.ctrip.framework.apollo.portal.spi.UserService;
import org.springframework.util.CollectionUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
......
...@@ -40,7 +40,6 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -40,7 +40,6 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
ALL: 'all' ALL: 'all'
}; };
var MIN_ROW_SIZE = 10;
var operate_branch_storage_key = 'OperateBranch'; var operate_branch_storage_key = 'OperateBranch';
...@@ -642,7 +641,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -642,7 +641,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
function parseModel2Text(namespace) { function parseModel2Text(namespace) {
if (namespace.items.length == 0) { if (namespace.items.length == 0) {
namespace.itemCnt = MIN_ROW_SIZE; namespace.itemCnt = 0;
return ""; return "";
} }
...@@ -658,7 +657,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -658,7 +657,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
function parseNotPropertiesText(namespace) { function parseNotPropertiesText(namespace) {
var text = namespace.items[0].item.value; var text = namespace.items[0].item.value;
var lineNum = text.split("\n").length; var lineNum = text.split("\n").length;
namespace.itemCnt = lineNum < MIN_ROW_SIZE ? MIN_ROW_SIZE : lineNum; namespace.itemCnt = lineNum;
return text; return text;
} }
...@@ -682,7 +681,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -682,7 +681,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
itemCnt++; itemCnt++;
}); });
namespace.itemCnt = itemCnt < MIN_ROW_SIZE ? MIN_ROW_SIZE : itemCnt; namespace.itemCnt = itemCnt;
return result; return result;
} }
......
...@@ -295,13 +295,15 @@ ...@@ -295,13 +295,15 @@
</div> </div>
<!--text view--> <!--text view-->
<!--只读模式下的文本内容,不替换换行符--> <!--只读模式下的文本内容,不替换换行符-->
<textarea class="form-control no-radius" rows="{{namespace.itemCnt}}" <textarea class="form-control no-radius"
rows="{{namespace.itemCnt < 10 ? 10: namespace.itemCnt>20 ? 20:namespace.itemCnt}}"
ng-show="namespace.viewType == 'text' && !namespace.isTextEditing" ng-show="namespace.viewType == 'text' && !namespace.isTextEditing"
ng-disabled="!namespace.isTextEditing" ng-disabled="!namespace.isTextEditing"
ng-bind="namespace.text"> ng-bind="namespace.text">
</textarea> </textarea>
<!--编辑状态下的文本内容,会过滤掉换行符--> <!--编辑状态下的文本内容,会过滤掉换行符-->
<textarea class="form-control" rows="{{namespace.itemCnt}}" style="border-radius: 0px" <textarea class="form-control no-radius"
rows="{{namespace.itemCnt < 10 ? 10: namespace.itemCnt>20 ? 20:namespace.itemCnt}}"
ng-show="namespace.viewType == 'text' && namespace.isTextEditing" ng-show="namespace.viewType == 'text' && namespace.isTextEditing"
ng-disabled="!namespace.isTextEditing" ng-model="namespace.editText"> ng-disabled="!namespace.isTextEditing" ng-model="namespace.editText">
</textarea> </textarea>
...@@ -874,7 +876,8 @@ ...@@ -874,7 +876,8 @@
<!--gray rules--> <!--gray rules-->
<div class="rules-manage-view row" ng-show="namespace.branch.viewType == 'rule'"> <div class="rules-manage-view row" ng-show="namespace.branch.viewType == 'rule'">
<div class="alert alert-warning no-radius" ng-show="!namespace.hasModifyPermission && !namespace.hasReleasePermission"> <div class="alert alert-warning no-radius"
ng-show="!namespace.hasModifyPermission && !namespace.hasReleasePermission">
<strong>Tips:</strong> <strong>Tips:</strong>
您没有权限编辑灰度规则, 具有namespace修改权或者发布权的人员才可以编辑灰度规则. 如需要编辑灰度规则,请找项目管理员申请权限. 您没有权限编辑灰度规则, 具有namespace修改权或者发布权的人员才可以编辑灰度规则. 如需要编辑灰度规则,请找项目管理员申请权限.
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment