提交 72923ce6 编写于 作者: L lepdou

support send email when namespace released

上级 eadb0a59
......@@ -15,6 +15,7 @@ import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.Type;
......@@ -39,25 +40,58 @@ public class ReleaseHistoryController {
method = RequestMethod.GET)
public PageDTO<ReleaseHistoryDTO> findReleaseHistoriesByNamespace(
@PathVariable String appId, @PathVariable String clusterName,
@PathVariable String namespaceName, Pageable pageable) {
Page<ReleaseHistory> result = releaseHistoryService.findReleaseHistoriesByNamespace(appId,
clusterName, namespaceName, pageable);
@PathVariable String namespaceName,
Pageable pageable) {
if (!result.hasContent()) {
Page<ReleaseHistory> result = releaseHistoryService.findReleaseHistoriesByNamespace(appId, clusterName,
namespaceName, pageable);
return transform2PageDTO(result, pageable);
}
@RequestMapping(value = "/releases/histories/by_release_id_and_operation", method = RequestMethod.GET)
public PageDTO<ReleaseHistoryDTO> findReleaseHistoryByReleaseIdAndOperation(
@RequestParam("releaseId") long releaseId,
@RequestParam("operation") int operation,
Pageable pageable) {
Page<ReleaseHistory> result = releaseHistoryService.findByReleaseIdAndOperation(releaseId, operation, pageable);
return transform2PageDTO(result, pageable);
}
@RequestMapping(value = "/releases/histories/by_previous_release_id_and_operation", method = RequestMethod.GET)
public PageDTO<ReleaseHistoryDTO> findReleaseHistoryByPreviousReleaseIdAndOperation(
@RequestParam("previousReleaseId") long previousReleaseId,
@RequestParam("operation") int operation,
Pageable pageable) {
Page<ReleaseHistory> result = releaseHistoryService.findByPreviousReleaseIdAndOperation(previousReleaseId, operation, pageable);
return transform2PageDTO(result, pageable);
}
private PageDTO<ReleaseHistoryDTO> transform2PageDTO(Page<ReleaseHistory> releaseHistoriesPage, Pageable pageable){
if (!releaseHistoriesPage.hasContent()) {
return null;
}
List<ReleaseHistory> releaseHistories = result.getContent();
List<ReleaseHistory> releaseHistories = releaseHistoriesPage.getContent();
List<ReleaseHistoryDTO> releaseHistoryDTOs = new ArrayList<>(releaseHistories.size());
for (ReleaseHistory releaseHistory : releaseHistories) {
ReleaseHistoryDTO dto = new ReleaseHistoryDTO();
BeanUtils.copyProperties(releaseHistory, dto, "operationContext");
dto.setOperationContext(gson.fromJson(releaseHistory.getOperationContext(),
configurationTypeReference));
releaseHistoryDTOs.add(dto);
releaseHistoryDTOs.add(transformReleaseHistory2DTO(releaseHistory));
}
return new PageDTO<>(releaseHistoryDTOs, pageable, result.getTotalElements());
return new PageDTO<>(releaseHistoryDTOs, pageable, releaseHistoriesPage.getTotalElements());
}
private ReleaseHistoryDTO transformReleaseHistory2DTO(ReleaseHistory releaseHistory) {
ReleaseHistoryDTO dto = new ReleaseHistoryDTO();
BeanUtils.copyProperties(releaseHistory, dto, "operationContext");
dto.setOperationContext(gson.fromJson(releaseHistory.getOperationContext(),
configurationTypeReference));
return dto;
}
}
......@@ -24,6 +24,16 @@ public class Namespace extends BaseEntity {
@Column(name = "NamespaceName", nullable = false)
private String namespaceName;
public Namespace(){
}
public Namespace(String appId, String clusterName, String namespaceName) {
this.appId = appId;
this.clusterName = clusterName;
this.namespaceName = namespaceName;
}
public String getAppId() {
return appId;
}
......
......@@ -17,7 +17,9 @@ public interface ReleaseHistoryRepository extends PagingAndSortingRepository<Rel
Page<ReleaseHistory> findByAppIdAndClusterNameAndNamespaceNameOrderByIdDesc(String appId, String
clusterName, String namespaceName, Pageable pageable);
List<ReleaseHistory> findByReleaseId(long releaseId);
Page<ReleaseHistory> findByReleaseIdAndOperationOrderByIdDesc(long releaseId, int operation, Pageable pageable);
Page<ReleaseHistory> findByPreviousReleaseIdAndOperationOrderByIdDesc(long previousReleaseId, int operation, Pageable pageable);
@Modifying
@Query("update ReleaseHistory set isdeleted=1,DataChange_LastModifiedBy = ?4 where appId=?1 and clusterName=?2 and namespaceName = ?3")
......
......@@ -100,6 +100,10 @@ public class NamespaceService {
}
public Namespace findParentNamespace(String appId, String clusterName, String namespaceName){
return findParentNamespace(new Namespace(appId, clusterName, namespaceName));
}
public Namespace findParentNamespace(Namespace namespace) {
String appId = namespace.getAppId();
String namespaceName = namespace.getNamespaceName();
......@@ -113,6 +117,10 @@ public class NamespaceService {
return null;
}
public boolean isChildNamespace(String appId, String clusterName, String namespaceName){
return isChildNamespace(new Namespace(appId, clusterName, namespaceName));
}
public boolean isChildNamespace(Namespace namespace) {
return findParentNamespace(namespace) != null;
}
......
......@@ -13,7 +13,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
......@@ -21,13 +20,13 @@ import java.util.Map;
*/
@Service
public class ReleaseHistoryService {
private Gson gson = new Gson();
@Autowired
private ReleaseHistoryRepository releaseHistoryRepository;
@Autowired
private AuditService auditService;
private Gson gson = new Gson();
public Page<ReleaseHistory> findReleaseHistoriesByNamespace(String appId, String clusterName,
String namespaceName, Pageable
......@@ -36,14 +35,18 @@ public class ReleaseHistoryService {
namespaceName, pageable);
}
public List<ReleaseHistory> findReleaseHistoriesByReleaseId(long releaseId) {
return releaseHistoryRepository.findByReleaseId(releaseId);
public Page<ReleaseHistory> findByReleaseIdAndOperation(long releaseId, int operation, Pageable page) {
return releaseHistoryRepository.findByReleaseIdAndOperationOrderByIdDesc(releaseId, operation, page);
}
public Page<ReleaseHistory> findByPreviousReleaseIdAndOperation(long previousReleaseId, int operation, Pageable page) {
return releaseHistoryRepository.findByPreviousReleaseIdAndOperationOrderByIdDesc(previousReleaseId, operation, page);
}
@Transactional
public ReleaseHistory createReleaseHistory(String appId, String clusterName, String
namespaceName, String branchName, long releaseId, long previousReleaseId, int operation,
Map<String, Object> operationContext, String operator) {
Map<String, Object> operationContext, String operator) {
ReleaseHistory releaseHistory = new ReleaseHistory();
releaseHistory.setAppId(appId);
releaseHistory.setClusterName(clusterName);
......@@ -64,13 +67,13 @@ public class ReleaseHistoryService {
releaseHistoryRepository.save(releaseHistory);
auditService.audit(ReleaseHistory.class.getSimpleName(), releaseHistory.getId(),
Audit.OP.INSERT, releaseHistory.getDataChangeCreatedBy());
Audit.OP.INSERT, releaseHistory.getDataChangeCreatedBy());
return releaseHistory;
}
@Transactional
public int batchDelete(String appId, String clusterName, String namespaceName, String operator){
public int batchDelete(String appId, String clusterName, String namespaceName, String operator) {
return releaseHistoryRepository.batchDelete(appId, clusterName, namespaceName, operator);
}
}
......@@ -2,11 +2,16 @@ package com.ctrip.framework.apollo.common.constants;
import com.google.gson.reflect.TypeToken;
import com.ctrip.framework.apollo.common.dto.GrayReleaseRuleItemDTO;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public interface GsonType {
Type CONFIG = new TypeToken<Map<String, String>>() {}.getType();
Type RULE_ITEMS = new TypeToken<List<GrayReleaseRuleItemDTO>>() {}.getType();
}
......@@ -64,6 +64,10 @@
<groupId>com.ctrip.framework.apollo-sso</groupId>
<artifactId>apollo-sso-ctrip</artifactId>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo-ctrip-service</groupId>
<artifactId>apollo-email-service</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
......
......@@ -388,6 +388,17 @@ public class AdminServiceAPI {
type, appId, clusterName, namespaceName, page, size).getBody();
}
public PageDTO<ReleaseHistoryDTO> findByReleaseIdAndOperation(Env env, long releaseId, int operation, int page, int size) {
return restTemplate.get(env,
"/releases/histories/by_release_id_and_operation?releaseId={releaseId}&operation={operation}&page={page}&size={size}",
type, releaseId, operation, page, size).getBody();
}
public PageDTO<ReleaseHistoryDTO> findByPreviousReleaseIdAndOperation(Env env, long previousReleaseId, int operation, int page, int size) {
return restTemplate.get(env,
"/releases/histories/by_previous_release_id_and_operation?previousReleaseId={releaseId}&operation={operation}&page={page}&size={size}",
type, previousReleaseId, operation, page, size).getBody();
}
}
......
package com.ctrip.framework.apollo.portal.components.emailbuilder;
import com.ctrip.framework.apollo.common.constants.ReleaseOperation;
import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
import com.ctrip.framework.apollo.common.entity.AppNamespace;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.constant.RoleType;
import com.ctrip.framework.apollo.portal.entity.bo.Email;
import com.ctrip.framework.apollo.portal.entity.bo.ReleaseHistoryBO;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.entity.vo.Change;
import com.ctrip.framework.apollo.portal.entity.vo.ReleaseCompareResult;
import com.ctrip.framework.apollo.portal.service.AppNamespaceService;
import com.ctrip.framework.apollo.portal.service.ReleaseService;
import com.ctrip.framework.apollo.portal.service.RolePermissionService;
import com.ctrip.framework.apollo.portal.service.ServerConfigService;
import com.ctrip.framework.apollo.portal.util.RoleUtils;
import org.apache.commons.lang.time.FastDateFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.annotation.PostConstruct;
public abstract class ConfigPublishEmailBuilder {
//email content common field placeholder
private static final String EMAIL_CONTENT_FIELD_APPID = "\\$\\{appId\\}";
private static final String EMAIL_CONTENT_FIELD_ENV = "\\$\\{env}";
private static final String EMAIL_CONTENT_FIELD_CLUSTER = "\\$\\{clusterName}";
private static final String EMAIL_CONTENT_FIELD_NAMESPACE = "\\$\\{namespaceName}";
private static final String EMAIL_CONTENT_FIELD_OPERATOR = "\\$\\{operator}";
private static final String EMAIL_CONTENT_FIELD_RELEASE_TIME = "\\$\\{releaseTime}";
private static final String EMAIL_CONTENT_FIELD_RELEASE_ID = "\\$\\{releaseId}";
private static final String EMAIL_CONTENT_FIELD_RELEASE_TITLE = "\\$\\{releaseTitle}";
private static final String EMAIL_CONTENT_FIELD_RELEASE_COMMENT = "\\$\\{releaseComment}";
private static final String EMAIL_CONTENT_FIELD_APOLLO_SERVER_ADDRESS = "\\$\\{apollo.portal.address}";
private static final String EMAIL_CONTENT_FIELD_DIFF = "\\$\\{diff}";
//email content special field placeholder
protected static final String EMAIL_CONTENT_FIELD_RULE = "\\$\\{rules}";
//email content module switch
private static final String EMAIL_CONTENT_DIFF_HAS_CONTENT_SWITCH = "diff-hidden";
private static final String EMAIL_CONTENT_DIFF_HAS_NOT_CONTENT_SWITCH = "diff-empty-hidden";
protected static final String EMAIL_CONTENT_RULE_SWITCH = "rule-hidden";
//set config's value max length to protect email.
protected static final int VALUE_MAX_LENGTH = 100;
//email body template. config in db, so we can dynamic reject email content.
private static final String EMAIL_TEMPLATE__RELEASE = "email.template.release";
private static final String EMAIL_TEMPLATE__ROLLBACK = "email.template.rollback";
private FastDateFormat dateFormat = FastDateFormat.getInstance("yyyy-MM-dd hh:mm:ss");
private String emailAddressSuffix;
private String emailSender;
@Autowired
private ServerConfigService serverConfigService;
@Autowired
private RolePermissionService rolePermissionService;
@Autowired
private ReleaseService releaseService;
@Autowired
private AppNamespaceService appNamespaceService;
@PostConstruct
public void init() {
emailAddressSuffix = serverConfigService.getValue("email.address.suffix");
emailSender = serverConfigService.getValue("email.sender");
}
public Email build(Env env, ReleaseHistoryBO releaseHistory) {
Email email = new Email();
email.setSubject(subject());
email.setSenderEmailAddress(emailSender);
email.setBody(emailContent(env, releaseHistory));
email.setRecipients(recipients(releaseHistory.getAppId(), releaseHistory.getNamespaceName()));
return email;
}
protected abstract String subject();
protected abstract String emailContent(Env env, ReleaseHistoryBO releaseHistory);
private List<String> recipients(String appId, String namespaceName) {
Set<UserInfo> modifyRoleUsers =
rolePermissionService
.queryUsersWithRole(RoleUtils.buildNamespaceRoleName(appId, namespaceName, RoleType.MODIFY_NAMESPACE));
Set<UserInfo> releaseRoleUsers =
rolePermissionService
.queryUsersWithRole(RoleUtils.buildNamespaceRoleName(appId, namespaceName, RoleType.RELEASE_NAMESPACE));
List<String> recipients = new ArrayList<>(modifyRoleUsers.size() + releaseRoleUsers.size());
for (UserInfo userInfo : modifyRoleUsers) {
recipients.add(userInfo.getUserId() + emailAddressSuffix);
}
for (UserInfo userInfo : releaseRoleUsers) {
recipients.add(userInfo.getUserId() + emailAddressSuffix);
}
return recipients;
}
protected String renderEmailCommonContent(String template, Env env, ReleaseHistoryBO releaseHistory) {
String renderResult = renderReleaseBasicInfo(template, env, releaseHistory);
renderResult = renderDiffContent(renderResult, env, releaseHistory);
return renderResult;
}
private String renderReleaseBasicInfo(String template, Env env, ReleaseHistoryBO releaseHistory) {
String renderResult = template.replaceAll(EMAIL_CONTENT_FIELD_APPID, releaseHistory.getAppId());
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_ENV, env.toString());
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_CLUSTER, releaseHistory.getClusterName());
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_NAMESPACE, releaseHistory.getNamespaceName());
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_OPERATOR, releaseHistory.getOperator());
renderResult = renderResult.replaceAll(EMAIL_CONTENT_FIELD_RELEASE_TITLE, releaseHistory.getReleaseTitle());
renderResult =
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_APOLLO_SERVER_ADDRESS, getApolloPortalAddress());
return renderResult
.replaceAll(EMAIL_CONTENT_FIELD_RELEASE_TIME, dateFormat.format(releaseHistory.getReleaseTime()));
}
private String renderDiffContent(String template, Env env, ReleaseHistoryBO releaseHistory) {
String appId = releaseHistory.getAppId();
String namespaceName = releaseHistory.getNamespaceName();
AppNamespace appNamespace = appNamespaceService.findByAppIdAndName(appId, namespaceName);
if (appNamespace == null) {
appNamespace = appNamespaceService.findPublicAppNamespace(namespaceName);
}
//don't show diff content if namespace's format is file
if (appNamespace == null ||
!appNamespace.getFormat().equals(ConfigFileFormat.Properties.getValue())) {
return template;
}
ReleaseCompareResult result = getReleaseCompareResult(env, releaseHistory);
if (!result.hasContent()) {
String renderResult = template.replaceAll(EMAIL_CONTENT_DIFF_HAS_NOT_CONTENT_SWITCH, "");
return renderResult.replaceAll(EMAIL_CONTENT_FIELD_DIFF, "");
}
List<Change> changes = result.getChanges();
StringBuilder changesHtmlBuilder = new StringBuilder();
for (Change change : changes) {
String key = change.getEntity().getFirstEntity().getKey();
String oldValue = change.getEntity().getFirstEntity().getValue();
String newValue = change.getEntity().getSecondEntity().getValue();
newValue = newValue == null ? "" : newValue;
changesHtmlBuilder.append("<tr>");
changesHtmlBuilder.append("<td width=\"10%\">").append(change.getType().toString()).append("</td>");
changesHtmlBuilder.append("<td width=\"10%\">").append(cutOffString(key)).append("</td>");
changesHtmlBuilder.append("<td width=\"10%\">").append(cutOffString(oldValue)).append("</td>");
changesHtmlBuilder.append("<td width=\"10%\">").append(cutOffString(newValue)).append("</td>");
changesHtmlBuilder.append("</tr>");
}
String renderResult = template.replaceAll(EMAIL_CONTENT_FIELD_DIFF, changesHtmlBuilder.toString());
return renderResult.replaceAll(EMAIL_CONTENT_DIFF_HAS_CONTENT_SWITCH, "");
}
private ReleaseCompareResult getReleaseCompareResult(Env env, ReleaseHistoryBO releaseHistory) {
if (releaseHistory.getOperation() == ReleaseOperation.GRAY_RELEASE
&& releaseHistory.getPreviousReleaseId() == 0) {
ReleaseDTO masterLatestActiveRelease = releaseService.loadLatestRelease(
releaseHistory.getAppId(), env, releaseHistory.getClusterName(), releaseHistory.getNamespaceName());
ReleaseDTO branchLatestActiveRelease = releaseService.findReleaseById(env, releaseHistory.getReleaseId());
return releaseService.compare(masterLatestActiveRelease, branchLatestActiveRelease);
}
return releaseService.compare(env, releaseHistory.getPreviousReleaseId(), releaseHistory.getReleaseId());
}
protected String getReleaseTemplate() {
return serverConfigService.getValue(EMAIL_TEMPLATE__RELEASE);
}
protected String getRollbackTemplate() {
return serverConfigService.getValue(EMAIL_TEMPLATE__ROLLBACK);
}
protected String getApolloPortalAddress() {
return serverConfigService.getValue("apollo.portal.address");
}
private String cutOffString(String source) {
if (source.length() > VALUE_MAX_LENGTH) {
return source.substring(0, VALUE_MAX_LENGTH) + "...";
}
return source;
}
}
package com.ctrip.framework.apollo.portal.components.emailbuilder;
import com.google.gson.Gson;
import com.ctrip.framework.apollo.common.constants.GsonType;
import com.ctrip.framework.apollo.common.dto.GrayReleaseRuleItemDTO;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.entity.bo.ReleaseHistoryBO;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Component
public class GrayPublishEmailBuilder extends ConfigPublishEmailBuilder {
private static final String EMAIL_SUBJECT = "[Apollo] 灰度发布";
private Gson gson = new Gson();
@Override
protected String subject() {
return EMAIL_SUBJECT;
}
@Override
public String emailContent(Env env, ReleaseHistoryBO releaseHistory) {
String result = renderEmailCommonContent(getReleaseTemplate(), env, releaseHistory);
return renderGrayReleaseRuleContent(result, releaseHistory);
}
private String renderGrayReleaseRuleContent(String template, ReleaseHistoryBO releaseHistory) {
String result = template.replaceAll(EMAIL_CONTENT_RULE_SWITCH, "");
Map<String, Object> context = releaseHistory.getOperationContext();
Object rules = context.get("rules");
List<GrayReleaseRuleItemDTO>
ruleItems = rules == null ?
null : gson.fromJson(rules.toString(), GsonType.RULE_ITEMS);
StringBuilder rulesHtmlBuilder = new StringBuilder();
if (CollectionUtils.isEmpty(ruleItems)) {
rulesHtmlBuilder.append("无灰度规则");
} else {
for (GrayReleaseRuleItemDTO ruleItem : ruleItems) {
String clientAppId = ruleItem.getClientAppId();
Set<String> ips = ruleItem.getClientIpList();
rulesHtmlBuilder.append("<b>AppId:&nbsp;</b>")
.append(clientAppId)
.append("&nbsp;&nbsp; <b>IP:&nbsp;</b>");
for (String ip : ips) {
rulesHtmlBuilder.append(ip).append(",");
}
}
}
return result.replaceAll(EMAIL_CONTENT_FIELD_RULE, rulesHtmlBuilder.toString());
}
}
package com.ctrip.framework.apollo.portal.components.emailbuilder;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.entity.bo.ReleaseHistoryBO;
import org.springframework.stereotype.Component;
@Component
public class MergeEmailBuilder extends ConfigPublishEmailBuilder {
private static final String EMAIL_SUBJECT = "[Apollo] 全量发布";
@Override
protected String subject() {
return EMAIL_SUBJECT;
}
@Override
protected String emailContent(Env env, ReleaseHistoryBO releaseHistory) {
String template = getReleaseTemplate();
return renderEmailCommonContent(template, env, releaseHistory);
}
}
package com.ctrip.framework.apollo.portal.components.emailbuilder;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.entity.bo.ReleaseHistoryBO;
import org.springframework.stereotype.Component;
@Component
public class NormalPublishEmailBuilder extends ConfigPublishEmailBuilder {
private static final String EMAIL_SUBJECT = "[Apollo] 配置发布";
@Override
protected String subject() {
return EMAIL_SUBJECT;
}
@Override
protected String emailContent(Env env, ReleaseHistoryBO releaseHistory) {
String template = getReleaseTemplate();
return renderEmailCommonContent(template, env, releaseHistory);
}
}
package com.ctrip.framework.apollo.portal.components.emailbuilder;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.entity.bo.ReleaseHistoryBO;
import org.springframework.stereotype.Component;
@Component
public class RollbackEmailBuilder extends ConfigPublishEmailBuilder {
private static final String EMAIL_SUBJECT = "[Apollo] 配置回滚";
@Override
protected String subject() {
return EMAIL_SUBJECT;
}
@Override
protected String emailContent(Env env, ReleaseHistoryBO releaseHistory) {
String template = getRollbackTemplate();
return renderEmailCommonContent(template, env, releaseHistory);
}
}
......@@ -11,7 +11,7 @@ import com.ctrip.framework.apollo.common.utils.InputValidator;
import com.ctrip.framework.apollo.common.utils.RequestPrecondition;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.components.PortalSettings;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.entity.vo.EnvClusterInfo;
import com.ctrip.framework.apollo.portal.listener.AppCreationEvent;
import com.ctrip.framework.apollo.portal.service.AppService;
......
......@@ -7,10 +7,12 @@ import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.components.PermissionValidator;
import com.ctrip.framework.apollo.portal.entity.model.NamespaceReleaseModel;
import com.ctrip.framework.apollo.portal.entity.vo.NamespaceVO;
import com.ctrip.framework.apollo.portal.listener.ConfigPublishEvent;
import com.ctrip.framework.apollo.portal.service.NamespaceBranchService;
import com.ctrip.framework.apollo.portal.service.ReleaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
......@@ -29,6 +31,8 @@ public class NamespaceBranchController {
private ReleaseService releaseService;
@Autowired
private NamespaceBranchService namespaceBranchService;
@Autowired
private ApplicationEventPublisher publisher;
@RequestMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches")
public NamespaceVO findBranch(@PathVariable String appId,
......@@ -80,9 +84,20 @@ public class NamespaceBranchController {
@PathVariable String branchName, @RequestParam(value = "deleteBranch", defaultValue = "true") boolean deleteBranch,
@RequestBody NamespaceReleaseModel model) {
return namespaceBranchService.merge(appId, Env.valueOf(env), clusterName, namespaceName, branchName,
ReleaseDTO createdRelease = namespaceBranchService.merge(appId, Env.valueOf(env), clusterName, namespaceName, branchName,
model.getReleaseTitle(), model.getReleaseComment(), deleteBranch);
ConfigPublishEvent event = ConfigPublishEvent.instance();
event.withAppId(appId)
.withCluster(clusterName)
.withNamespace(namespaceName)
.withReleaseId(createdRelease.getId())
.setMergeEvent(true)
.setEnv(Env.valueOf(env));
publisher.publishEvent(event);
return createdRelease;
}
......
......@@ -5,7 +5,7 @@ import com.google.common.collect.Sets;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.utils.RequestPrecondition;
import com.ctrip.framework.apollo.portal.constant.RoleType;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.entity.vo.AppRolesAssignedUsers;
import com.ctrip.framework.apollo.portal.entity.vo.NamespaceRolesAssignedUsers;
import com.ctrip.framework.apollo.portal.entity.vo.PermissionCondition;
......
......@@ -6,9 +6,11 @@ import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.entity.model.NamespaceReleaseModel;
import com.ctrip.framework.apollo.portal.entity.vo.ReleaseCompareResult;
import com.ctrip.framework.apollo.portal.entity.vo.ReleaseVO;
import com.ctrip.framework.apollo.portal.listener.ConfigPublishEvent;
import com.ctrip.framework.apollo.portal.service.ReleaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
......@@ -26,9 +28,11 @@ public class ReleaseController {
@Autowired
private ReleaseService releaseService;
@Autowired
private ApplicationEventPublisher publisher;
@PreAuthorize(value = "@permissionValidator.hasReleaseNamespacePermission(#appId, #namespaceName)")
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/release", method = RequestMethod.POST)
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/releases", method = RequestMethod.POST)
public ReleaseDTO createRelease(@PathVariable String appId,
@PathVariable String env, @PathVariable String clusterName,
@PathVariable String namespaceName, @RequestBody NamespaceReleaseModel model) {
......@@ -39,7 +43,48 @@ public class ReleaseController {
model.setClusterName(clusterName);
model.setNamespaceName(namespaceName);
return releaseService.publish(model);
ReleaseDTO createdRelease = releaseService.publish(model);
ConfigPublishEvent event = ConfigPublishEvent.instance();
event.withAppId(appId)
.withCluster(clusterName)
.withNamespace(namespaceName)
.withReleaseId(createdRelease.getId())
.setNormalPublishEvent(true)
.setEnv(Env.valueOf(env));
publisher.publishEvent(event);
return createdRelease;
}
@PreAuthorize(value = "@permissionValidator.hasReleaseNamespacePermission(#appId, #namespaceName)")
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/releases",
method = RequestMethod.POST)
public ReleaseDTO createGrayRelease(@PathVariable String appId,
@PathVariable String env, @PathVariable String clusterName,
@PathVariable String namespaceName, @PathVariable String branchName,
@RequestBody NamespaceReleaseModel model) {
checkModel(model != null);
model.setAppId(appId);
model.setEnv(env);
model.setClusterName(branchName);
model.setNamespaceName(namespaceName);
ReleaseDTO createdRelease = releaseService.publish(model);
ConfigPublishEvent event = ConfigPublishEvent.instance();
event.withAppId(appId)
.withCluster(clusterName)
.withNamespace(namespaceName)
.withReleaseId(createdRelease.getId())
.setGrayPublishEvent(true)
.setEnv(Env.valueOf(env));
publisher.publishEvent(event);
return createdRelease;
}
......@@ -84,5 +129,19 @@ public class ReleaseController {
public void rollback(@PathVariable String env,
@PathVariable long releaseId) {
releaseService.rollback(Env.valueOf(env), releaseId);
ReleaseDTO release = releaseService.findReleaseById(Env.valueOf(env), releaseId);
if (release == null) {
return;
}
ConfigPublishEvent event = ConfigPublishEvent.instance();
event.withAppId(release.getAppId())
.withCluster(release.getClusterName())
.withNamespace(release.getNamespaceName())
.withPreviousReleaseId(releaseId)
.setRollbackEvent(true)
.setEnv(Env.valueOf(env));
publisher.publishEvent(event);
}
}
......@@ -2,7 +2,7 @@ package com.ctrip.framework.apollo.portal.controller;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.entity.vo.ReleaseHistoryVO;
import com.ctrip.framework.apollo.portal.entity.bo.ReleaseHistoryBO;
import com.ctrip.framework.apollo.portal.service.ReleaseHistoryService;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -22,7 +22,7 @@ public class ReleaseHistoryController {
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/releases/histories",
method = RequestMethod.GET)
public List<ReleaseHistoryVO> findReleaseHistoriesByNamespace(@PathVariable String appId,
public List<ReleaseHistoryBO> findReleaseHistoriesByNamespace(@PathVariable String appId,
@PathVariable String env,
@PathVariable String clusterName,
@PathVariable String namespaceName,
......
package com.ctrip.framework.apollo.portal.controller;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.spi.LogoutHandler;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.spi.UserService;
import org.springframework.beans.factory.annotation.Autowired;
......
package com.ctrip.framework.apollo.portal.entity.bo;
import java.util.List;
public class Email {
private String senderEmailAddress;
private List<String> recipients;
private String subject;
private String body;
public String getSenderEmailAddress() {
return senderEmailAddress;
}
public void setSenderEmailAddress(String senderEmailAddress) {
this.senderEmailAddress = senderEmailAddress;
}
public List<String> getRecipients() {
return recipients;
}
public void setRecipients(List<String> recipients) {
this.recipients = recipients;
}
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;
}
}
package com.ctrip.framework.apollo.portal.entity.vo;
package com.ctrip.framework.apollo.portal.entity.bo;
import com.ctrip.framework.apollo.common.entity.EntityPair;
......@@ -6,7 +6,7 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
public class ReleaseHistoryVO {
public class ReleaseHistoryBO {
private long id;
......
package com.ctrip.framework.apollo.portal.entity.po;
package com.ctrip.framework.apollo.portal.entity.bo;
public class UserInfo {
......
package com.ctrip.framework.apollo.portal.entity.vo;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import java.util.Set;
......
package com.ctrip.framework.apollo.portal.entity.vo;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import java.util.Set;
......
......@@ -14,6 +14,10 @@ public class ReleaseCompareResult {
changes.add(new Change(type, new EntityPair<>(firstEntity, secondEntity)));
}
public boolean hasContent(){
return !changes.isEmpty();
}
public List<Change> getChanges() {
return changes;
}
......
package com.ctrip.framework.apollo.portal.listener;
import com.ctrip.framework.apollo.core.enums.Env;
import org.springframework.context.ApplicationEvent;
public class ConfigPublishEvent extends ApplicationEvent {
private ConfigPublishInfo configPublishInfo;
public ConfigPublishEvent(Object source) {
super(source);
configPublishInfo = (ConfigPublishInfo) source;
}
public static ConfigPublishEvent instance() {
ConfigPublishInfo info = new ConfigPublishInfo();
return new ConfigPublishEvent(info);
}
public ConfigPublishInfo getConfigPublishInfo(){
return configPublishInfo;
}
public ConfigPublishEvent withAppId(String appId) {
configPublishInfo.setAppId(appId);
return this;
}
public ConfigPublishEvent withCluster(String clusterName) {
configPublishInfo.setClusterName(clusterName);
return this;
}
public ConfigPublishEvent withNamespace(String namespaceName) {
configPublishInfo.setNamespaceName(namespaceName);
return this;
}
public ConfigPublishEvent withReleaseId(long releaseId){
configPublishInfo.setReleaseId(releaseId);
return this;
}
public ConfigPublishEvent withPreviousReleaseId(long previousReleaseId){
configPublishInfo.setPreviousReleaseId(previousReleaseId);
return this;
}
public ConfigPublishEvent setNormalPublishEvent(boolean isNormalPublishEvent) {
configPublishInfo.setNormalPublishEvent(isNormalPublishEvent);
return this;
}
public ConfigPublishEvent setGrayPublishEvent(boolean isGrayPublishEvent) {
configPublishInfo.setGrayPublishEvent(isGrayPublishEvent);
return this;
}
public ConfigPublishEvent setRollbackEvent(boolean isRollbackEvent) {
configPublishInfo.setRollbackEvent(isRollbackEvent);
return this;
}
public ConfigPublishEvent setMergeEvent(boolean isMergeEvent) {
configPublishInfo.setMergeEvent(isMergeEvent);
return this;
}
public ConfigPublishEvent setEnv(Env env) {
configPublishInfo.setEnv(env);
return this;
}
public static class ConfigPublishInfo {
private Env env;
private String appId;
private String clusterName;
private String namespaceName;
private long releaseId;
private long previousReleaseId;
private boolean isRollbackEvent;
private boolean isMergeEvent;
private boolean isNormalPublishEvent;
private boolean isGrayPublishEvent;
public Env getEnv() {
return env;
}
public void setEnv(Env env) {
this.env = env;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getClusterName() {
return clusterName;
}
public void setClusterName(String clusterName) {
this.clusterName = clusterName;
}
public String getNamespaceName() {
return namespaceName;
}
public void setNamespaceName(String namespaceName) {
this.namespaceName = namespaceName;
}
public long getReleaseId() {
return releaseId;
}
public void setReleaseId(long releaseId) {
this.releaseId = releaseId;
}
public long getPreviousReleaseId() {
return previousReleaseId;
}
public void setPreviousReleaseId(long previousReleaseId) {
this.previousReleaseId = previousReleaseId;
}
public boolean isRollbackEvent() {
return isRollbackEvent;
}
public void setRollbackEvent(boolean rollbackEvent) {
isRollbackEvent = rollbackEvent;
}
public boolean isMergeEvent() {
return isMergeEvent;
}
public void setMergeEvent(boolean mergeEvent) {
isMergeEvent = mergeEvent;
}
public boolean isNormalPublishEvent() {
return isNormalPublishEvent;
}
public void setNormalPublishEvent(boolean normalPublishEvent) {
isNormalPublishEvent = normalPublishEvent;
}
public boolean isGrayPublishEvent() {
return isGrayPublishEvent;
}
public void setGrayPublishEvent(boolean grayPublishEvent) {
isGrayPublishEvent = grayPublishEvent;
}
}
}
package com.ctrip.framework.apollo.portal.listener;
import com.ctrip.framework.apollo.common.constants.ReleaseOperation;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.components.emailbuilder.GrayPublishEmailBuilder;
import com.ctrip.framework.apollo.portal.components.emailbuilder.MergeEmailBuilder;
import com.ctrip.framework.apollo.portal.components.emailbuilder.NormalPublishEmailBuilder;
import com.ctrip.framework.apollo.portal.components.emailbuilder.RollbackEmailBuilder;
import com.ctrip.framework.apollo.portal.entity.bo.Email;
import com.ctrip.framework.apollo.portal.entity.bo.ReleaseHistoryBO;
import com.ctrip.framework.apollo.portal.service.ReleaseHistoryService;
import com.ctrip.framework.apollo.portal.service.ServerConfigService;
import com.ctrip.framework.apollo.portal.spi.EmailService;
import com.ctrip.framework.apollo.tracer.Tracer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.PostConstruct;
@Component
public class ConfigPublishListener {
@Autowired
private ServerConfigService serverConfigService;
@Autowired
private ReleaseHistoryService releaseHistoryService;
@Autowired
private EmailService emailService;
@Autowired
private NormalPublishEmailBuilder normalPublishEmailBuilder;
@Autowired
private GrayPublishEmailBuilder grayPublishEmailBuilder;
@Autowired
private RollbackEmailBuilder rollbackEmailBuilder;
@Autowired
private MergeEmailBuilder mergeEmailBuilder;
private Set<Env> emailSupportedEnvs = new HashSet<>();
@PostConstruct
public void init() {
try {
String sendEmailSwitchConfig =
serverConfigService.getValue("email.supported.envs", "PRO");
String[] supportedEnvs = sendEmailSwitchConfig.split(",");
for (String env : supportedEnvs) {
emailSupportedEnvs.add(Env.fromString(env.trim()));
}
} catch (Exception e) {
Tracer.logError("init email supported envs failed.", e);
}
}
@EventListener
public void onConfigPublish(ConfigPublishEvent event) {
Env env = event.getConfigPublishInfo().getEnv();
if (!emailSupportedEnvs.contains(env)) {
return;
}
ReleaseHistoryBO releaseHistory = getReleaseHistory(event);
if (releaseHistory == null) {
Tracer.logError("Will not send email, because load release history error", null);
return;
}
int realOperation = releaseHistory.getOperation();
Email email = buildEmail(env, releaseHistory, realOperation);
if (email != null) {
emailService.send(email);
}
}
private ReleaseHistoryBO getReleaseHistory(ConfigPublishEvent event) {
ConfigPublishEvent.ConfigPublishInfo info = event.getConfigPublishInfo();
Env env = info.getEnv();
int operation = info.isMergeEvent() ? ReleaseOperation.GRAY_RELEASE_MERGE_TO_MASTER :
info.isRollbackEvent() ? ReleaseOperation.ROLLBACK :
info.isNormalPublishEvent() ? ReleaseOperation.NORMAL_RELEASE :
info.isGrayPublishEvent() ? ReleaseOperation.GRAY_RELEASE : -1;
if (operation == -1) {
return null;
}
if (info.isRollbackEvent()) {
return releaseHistoryService
.findLatestByPreviousReleaseIdAndOperation(env, info.getPreviousReleaseId(), operation);
}else {
return releaseHistoryService.findLatestByReleaseIdAndOperation(env, info.getReleaseId(), operation);
}
}
private Email buildEmail(Env env, ReleaseHistoryBO releaseHistory, int operation) {
switch (operation) {
case ReleaseOperation.GRAY_RELEASE: {
return grayPublishEmailBuilder.build(env, releaseHistory);
}
case ReleaseOperation.NORMAL_RELEASE: {
return normalPublishEmailBuilder.build(env, releaseHistory);
}
case ReleaseOperation.ROLLBACK: {
return rollbackEmailBuilder.build(env, releaseHistory);
}
case ReleaseOperation.GRAY_RELEASE_MERGE_TO_MASTER: {
return mergeEmailBuilder.build(env, releaseHistory);
}
default:
return null;
}
}
}
......@@ -2,7 +2,7 @@ package com.ctrip.framework.apollo.portal.service;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.portal.entity.po.Favorite;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.repository.FavoriteRepository;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.spi.UserService;
......
......@@ -10,7 +10,7 @@ import com.ctrip.framework.apollo.common.entity.EntityPair;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.api.AdminServiceAPI;
import com.ctrip.framework.apollo.portal.entity.vo.ReleaseHistoryVO;
import com.ctrip.framework.apollo.portal.entity.bo.ReleaseHistoryBO;
import com.ctrip.framework.apollo.portal.util.RelativeDateFormat;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -36,7 +36,29 @@ public class ReleaseHistoryService {
private ReleaseService releaseService;
public List<ReleaseHistoryVO> findNamespaceReleaseHistory(String appId, Env env, String clusterName,
public ReleaseHistoryBO findLatestByReleaseIdAndOperation(Env env, long releaseId, int operation){
PageDTO<ReleaseHistoryDTO> pageDTO = releaseHistoryAPI.findByReleaseIdAndOperation(env, releaseId, operation, 0, 1);
if (pageDTO != null && pageDTO.hasContent()){
ReleaseHistoryDTO releaseHistory = pageDTO.getContent().get(0);
ReleaseDTO release = releaseService.findReleaseById(env, releaseHistory.getReleaseId());
return transformReleaseHistoryDTO2BO(releaseHistory, release);
}
return null;
}
public ReleaseHistoryBO findLatestByPreviousReleaseIdAndOperation(Env env, long previousReleaseId, int operation){
PageDTO<ReleaseHistoryDTO> pageDTO = releaseHistoryAPI.findByPreviousReleaseIdAndOperation(env, previousReleaseId, operation, 0, 1);
if (pageDTO != null && pageDTO.hasContent()){
ReleaseHistoryDTO releaseHistory = pageDTO.getContent().get(0);
ReleaseDTO release = releaseService.findReleaseById(env, releaseHistory.getReleaseId());
return transformReleaseHistoryDTO2BO(releaseHistory, release);
}
return null;
}
public List<ReleaseHistoryBO> findNamespaceReleaseHistory(String appId, Env env, String clusterName,
String namespaceName, int page, int size) {
PageDTO<ReleaseHistoryDTO> result = releaseHistoryAPI.findReleaseHistoriesByNamespace(appId, env, clusterName,
namespaceName, page, size);
......@@ -55,44 +77,47 @@ public class ReleaseHistoryService {
List<ReleaseDTO> releases = releaseService.findReleaseByIds(env, releaseIds);
return convertReleaseHistoryDTO2VO(content, releases);
return transformReleaseHistoryDTO2BO(content, releases);
}
private List<ReleaseHistoryVO> convertReleaseHistoryDTO2VO(List<ReleaseHistoryDTO> source,
List<ReleaseDTO> releases) {
private List<ReleaseHistoryBO> transformReleaseHistoryDTO2BO(List<ReleaseHistoryDTO> source,
List<ReleaseDTO> releases) {
Map<Long, ReleaseDTO> releasesMap = BeanUtils.mapByKey("id", releases);
List<ReleaseHistoryVO> vos = new ArrayList<>(source.size());
List<ReleaseHistoryBO> bos = new ArrayList<>(source.size());
for (ReleaseHistoryDTO dto : source) {
ReleaseHistoryVO vo = new ReleaseHistoryVO();
vo.setId(dto.getId());
vo.setAppId(dto.getAppId());
vo.setClusterName(dto.getClusterName());
vo.setNamespaceName(dto.getNamespaceName());
vo.setBranchName(dto.getBranchName());
vo.setReleaseId(dto.getReleaseId());
vo.setPreviousReleaseId(dto.getPreviousReleaseId());
vo.setOperator(dto.getDataChangeCreatedBy());
vo.setOperation(dto.getOperation());
Date releaseTime = dto.getDataChangeLastModifiedTime();
vo.setReleaseTime(releaseTime);
vo.setReleaseTimeFormatted(RelativeDateFormat.format(releaseTime));
vo.setOperationContext(dto.getOperationContext());
//set release info
ReleaseDTO release = releasesMap.get(dto.getReleaseId());
setReleaseInfoToReleaseHistoryVO(vo, release);
vos.add(vo);
bos.add(transformReleaseHistoryDTO2BO(dto, release));
}
return vos;
return bos;
}
private void setReleaseInfoToReleaseHistoryVO(ReleaseHistoryVO vo, ReleaseDTO release) {
private ReleaseHistoryBO transformReleaseHistoryDTO2BO(ReleaseHistoryDTO dto, ReleaseDTO release){
ReleaseHistoryBO bo = new ReleaseHistoryBO();
bo.setId(dto.getId());
bo.setAppId(dto.getAppId());
bo.setClusterName(dto.getClusterName());
bo.setNamespaceName(dto.getNamespaceName());
bo.setBranchName(dto.getBranchName());
bo.setReleaseId(dto.getReleaseId());
bo.setPreviousReleaseId(dto.getPreviousReleaseId());
bo.setOperator(dto.getDataChangeCreatedBy());
bo.setOperation(dto.getOperation());
Date releaseTime = dto.getDataChangeLastModifiedTime();
bo.setReleaseTime(releaseTime);
bo.setReleaseTimeFormatted(RelativeDateFormat.format(releaseTime));
bo.setOperationContext(dto.getOperationContext());
//set release info
setReleaseInfoToReleaseHistoryBO(bo, release);
return bo;
}
private void setReleaseInfoToReleaseHistoryBO(ReleaseHistoryBO bo, ReleaseDTO release) {
if (release != null) {
vo.setReleaseTitle(release.getName());
vo.setReleaseComment(release.getComment());
bo.setReleaseTitle(release.getName());
bo.setReleaseComment(release.getComment());
Map<String, String> configuration = gson.fromJson(release.getConfigurations(), GsonType.CONFIG);
List<EntityPair<String>> items = new ArrayList<>(configuration.size());
......@@ -100,11 +125,11 @@ public class ReleaseHistoryService {
EntityPair<String> entityPair = new EntityPair<>(entry.getKey(), entry.getValue());
items.add(entityPair);
}
vo.setConfiguration(items);
bo.setConfiguration(items);
} else {
vo.setReleaseTitle("no release information");
vo.setConfiguration(null);
bo.setReleaseTitle("no release information");
bo.setConfiguration(null);
}
}
}
......@@ -2,8 +2,8 @@ package com.ctrip.framework.apollo.portal.service;
import com.google.common.base.Objects;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.ctrip.framework.apollo.common.constants.GsonType;
import com.ctrip.framework.apollo.common.dto.ItemChangeSets;
import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
import com.ctrip.framework.apollo.core.enums.Env;
......@@ -22,9 +22,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
......@@ -33,10 +33,8 @@ import java.util.Set;
@Service
public class ReleaseService {
private static final Gson gson = new Gson();
private static final Type configurationTypeReference =
new TypeToken<Map<String, String>>() {
}.getType();
@Autowired
private UserInfoHolder userInfoHolder;
......@@ -60,9 +58,11 @@ public class ReleaseService {
}
public ReleaseDTO updateAndPublish(String appId, Env env, String clusterName, String namespaceName,
String releaseTitle, String releaseComment, String branchName, boolean deleteBranch, ItemChangeSets changeSets){
String releaseTitle, String releaseComment, String branchName,
boolean deleteBranch, ItemChangeSets changeSets) {
return releaseAPI.updateAndPublish(appId, env, clusterName, namespaceName, releaseTitle, releaseComment, branchName, deleteBranch, changeSets);
return releaseAPI.updateAndPublish(appId, env, clusterName, namespaceName, releaseTitle, releaseComment, branchName,
deleteBranch, changeSets);
}
public List<ReleaseVO> findAllReleases(String appId, Env env, String clusterName, String namespaceName, int page,
......@@ -79,7 +79,7 @@ public class ReleaseService {
release.setBaseInfo(releaseDTO);
Set<KVEntity> kvEntities = new LinkedHashSet<>();
Map<String, String> configurations = gson.fromJson(releaseDTO.getConfigurations(), configurationTypeReference);
Map<String, String> configurations = gson.fromJson(releaseDTO.getConfigurations(), GsonType.CONFIG);
Set<Map.Entry<String, String>> entries = configurations.entrySet();
for (Map.Entry<String, String> entry : entries) {
kvEntities.add(new KVEntity(entry.getKey(), entry.getValue()));
......@@ -98,7 +98,19 @@ public class ReleaseService {
return releaseAPI.findActiveReleases(appId, env, clusterName, namespaceName, page, size);
}
public List<ReleaseDTO> findReleaseByIds(Env env, Set<Long> releaseIds){
public ReleaseDTO findReleaseById(Env env, long releaseId) {
Set<Long> releaseIds = new HashSet<>(1);
releaseIds.add(releaseId);
List<ReleaseDTO> releases = findReleaseByIds(env, releaseIds);
if (CollectionUtils.isEmpty(releases)) {
return null;
} else {
return releases.get(0);
}
}
public List<ReleaseDTO> findReleaseByIds(Env env, Set<Long> releaseIds) {
return releaseAPI.findReleaseByIds(env, releaseIds);
}
......@@ -111,19 +123,27 @@ public class ReleaseService {
}
public ReleaseCompareResult compare(Env env, long baseReleaseId, long toCompareReleaseId) {
Map<String, String> baseReleaseConfiguration = new HashMap<>();
Map<String, String> toCompareReleaseConfiguration = new HashMap<>();
if (baseReleaseId != 0){
ReleaseDTO baseRelease = releaseAPI.loadRelease(env, baseReleaseId);
baseReleaseConfiguration = gson.fromJson(baseRelease.getConfigurations(), configurationTypeReference);
ReleaseDTO baseRelease = null;
ReleaseDTO toCompareRelease = null;
if (baseReleaseId != 0) {
baseRelease = releaseAPI.loadRelease(env, baseReleaseId);
}
if (toCompareReleaseId != 0){
ReleaseDTO toCompareRelease = releaseAPI.loadRelease(env, toCompareReleaseId);
toCompareReleaseConfiguration = gson.fromJson(toCompareRelease.getConfigurations(), configurationTypeReference);
if (toCompareReleaseId != 0) {
toCompareRelease = releaseAPI.loadRelease(env, toCompareReleaseId);
}
return compare(baseRelease, toCompareRelease);
}
public ReleaseCompareResult compare(ReleaseDTO baseRelease, ReleaseDTO toCompareRelease) {
Map<String, String> baseReleaseConfiguration = baseRelease == null ? new HashMap<>() :
gson.fromJson(baseRelease.getConfigurations(), GsonType.CONFIG);
Map<String, String> toCompareReleaseConfiguration = toCompareRelease == null ? new HashMap<>() :
gson.fromJson(toCompareRelease.getConfigurations(),
GsonType.CONFIG);
ReleaseCompareResult compareResult = new ReleaseCompareResult();
//added and modified in firstRelease
......@@ -134,10 +154,10 @@ public class ReleaseService {
//added
if (secondValue == null) {
compareResult.addEntityPair(ChangeType.DELETED, new KVEntity(key, firstValue),
new KVEntity(key, null));
new KVEntity(key, null));
} else if (!Objects.equal(firstValue, secondValue)) {
compareResult.addEntityPair(ChangeType.MODIFIED, new KVEntity(key, firstValue),
new KVEntity(key, secondValue));
new KVEntity(key, secondValue));
}
}
......
......@@ -12,7 +12,7 @@ import com.google.common.collect.Sets;
import com.ctrip.framework.apollo.portal.entity.po.Permission;
import com.ctrip.framework.apollo.portal.entity.po.Role;
import com.ctrip.framework.apollo.portal.entity.po.RolePermission;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.entity.po.UserRole;
import com.ctrip.framework.apollo.portal.repository.PermissionRepository;
import com.ctrip.framework.apollo.portal.repository.RolePermissionRepository;
......
package com.ctrip.framework.apollo.portal.spi;
import com.ctrip.framework.apollo.portal.entity.bo.Email;
public interface EmailService {
void send(Email email);
}
package com.ctrip.framework.apollo.portal.spi;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
/**
* Get access to the user's information,
......
package com.ctrip.framework.apollo.portal.spi;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import java.util.List;
......
package com.ctrip.framework.apollo.portal.spi.configuration;
import com.ctrip.framework.apollo.portal.spi.EmailService;
import com.ctrip.framework.apollo.portal.spi.ctrip.CtripEmailService;
import com.ctrip.framework.apollo.portal.spi.ctrip.CtripEmailRequestBuilder;
import com.ctrip.framework.apollo.portal.spi.defaultimpl.DefaultEmailService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
public class EmailConfiguration {
@Configuration
@Profile("ctrip")
public static class CtripEmailConfiguration{
@Bean
public EmailService ctripEmailService() {
return new CtripEmailService();
}
@Bean
public CtripEmailRequestBuilder emailRequestBuilder(){
return new CtripEmailRequestBuilder();
}
}
@Bean
@ConditionalOnMissingBean(EmailService.class)
public EmailService defaultEmailService() {
return new DefaultEmailService();
}
}
package com.ctrip.framework.apollo.portal.spi.ctrip;
import com.ctrip.framework.apollo.portal.entity.bo.Email;
import com.ctrip.framework.apollo.tracer.Tracer;
import org.apache.commons.lang.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
public class CtripEmailRequestBuilder {
private static final Logger logger = LoggerFactory.getLogger(CtripEmailRequestBuilder.class);
private static Class sendEmailRequestClazz;
private static Method setBodyContent;
private static Method setRecipient;
private static Method setSendCode;
private static Method setBodyTemplateID;
private static Method setSender;
private static Method setSubject;
private static Method setIsBodyHtml;
private static Method setCharset;
private static Method setExpiredTime;
private static Method setAppID;
@Value("${ctrip.appid}")
private int appId;
//send code & template id. apply from ewatch
@Value("${ctrip.email.send.code}")
private String sendCode;
@Value("${ctrip.email.template.id}")
private int templateId;
//email retention time in email server queue.TimeUnit: hour
@Value("${ctrip.email.survival.duration}")
private int survivalDuration;
private Calendar expiredTime;
@PostConstruct
public void init() {
try {
sendEmailRequestClazz = Class.forName("com.ctrip.framework.apolloctripservice.emailservice.SendEmailRequest");
setSendCode = sendEmailRequestClazz.getMethod("setSendCode", String.class);
setBodyTemplateID = sendEmailRequestClazz.getMethod("setBodyTemplateID", Integer.class);
setSender = sendEmailRequestClazz.getMethod("setSender", String.class);
setBodyContent = sendEmailRequestClazz.getMethod("setBodyContent", String.class);
setRecipient = sendEmailRequestClazz.getMethod("setRecipient", List.class);
setSubject = sendEmailRequestClazz.getMethod("setSubject", String.class);
setIsBodyHtml = sendEmailRequestClazz.getMethod("setIsBodyHtml", Boolean.class);
setCharset = sendEmailRequestClazz.getMethod("setCharset", String.class);
setExpiredTime = sendEmailRequestClazz.getMethod("setExpiredTime", Calendar.class);
setAppID = sendEmailRequestClazz.getMethod("setAppID", Integer.class);
expiredTime = calExpiredTime();
} catch (Throwable e) {
logger.error("init email request build failed", e);
Tracer.logError("init email request build failed", e);
}
}
public Object buildEmailRequest(Email email) throws Exception {
Object emailRequest = createBasicEmailRequest();
setSender.invoke(emailRequest, email.getSenderEmailAddress());
setSubject.invoke(emailRequest, email.getSubject());
setBodyContent.invoke(emailRequest, email.getBody());
setRecipient.invoke(emailRequest, email.getRecipients());
return emailRequest;
}
private Object createBasicEmailRequest() throws Exception {
Object request = sendEmailRequestClazz.newInstance();
setSendCode.invoke(request, sendCode);
setBodyTemplateID.invoke(request, templateId);
setIsBodyHtml.invoke(request, true);
setCharset.invoke(request, "UTF-8");
setExpiredTime.invoke(request, expiredTime);
setAppID.invoke(request, appId);
return request;
}
private Calendar calExpiredTime() {
Calendar calendar = Calendar.getInstance();
calendar.setTime(DateUtils.addHours(new Date(), survivalDuration));
return calendar;
}
}
package com.ctrip.framework.apollo.portal.spi.ctrip;
import com.ctrip.framework.apollo.portal.entity.bo.Email;
import com.ctrip.framework.apollo.portal.service.ServerConfigService;
import com.ctrip.framework.apollo.portal.spi.EmailService;
import com.ctrip.framework.apollo.tracer.Tracer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.reflect.Method;
import javax.annotation.PostConstruct;
public class CtripEmailService implements EmailService {
private static final Logger logger = LoggerFactory.getLogger(CtripEmailService.class);
private Object emailServiceClient;
private Method sendEmailAsync;
@Autowired
private CtripEmailRequestBuilder emailRequestBuilder;
@Autowired
private ServerConfigService serverConfigService;
@PostConstruct
public void init() {
try {
initServiceClientConfig();
Class emailServiceClientClazz =
Class.forName("com.ctrip.framework.apolloctripservice.emailservice.EmailServiceClient");
Method getInstanceMethod = emailServiceClientClazz.getMethod("getInstance");
emailServiceClient = getInstanceMethod.invoke(null);
Class sendEmailRequestClazz =
Class.forName("com.ctrip.framework.apolloctripservice.emailservice.SendEmailRequest");
sendEmailAsync = emailServiceClientClazz.getMethod("sendEmailAsync", sendEmailRequestClazz);
} catch (Throwable e) {
logger.error("init ctrip email service failed", e);
Tracer.logError("init ctrip email service failed", e);
}
}
private void initServiceClientConfig() throws Exception {
Class serviceClientConfigClazz = Class.forName("com.ctriposs.baiji.rpc.client.ServiceClientConfig");
Object serviceClientConfig = serviceClientConfigClazz.newInstance();
Method setFxConfigServiceUrlMethod = serviceClientConfigClazz.getMethod("setFxConfigServiceUrl", String.class);
String soaServerAddress = serverConfigService.getValue("soa.server.address");
setFxConfigServiceUrlMethod.invoke(serviceClientConfig, soaServerAddress);
Class serviceClientBaseClazz = Class.forName("com.ctriposs.baiji.rpc.client.ServiceClientBase");
Method initializeMethod = serviceClientBaseClazz.getMethod("initialize", serviceClientConfigClazz);
initializeMethod.invoke(null, serviceClientConfig);
}
@Override
public void send(Email email) {
try {
Object emailRequest = emailRequestBuilder.buildEmailRequest(email);
Object sendResponse = sendEmailAsync.invoke(emailServiceClient, emailRequest);
logger.info("Email sender response:" + sendResponse);
} catch (Throwable e) {
logger.error("send email failed", e);
Tracer.logError("send email failed", e);
}
}
}
package com.ctrip.framework.apollo.portal.spi.ctrip;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import java.lang.reflect.Method;
......
......@@ -4,7 +4,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.service.ServerConfigService;
import com.ctrip.framework.apollo.portal.spi.UserService;
......
package com.ctrip.framework.apollo.portal.spi.defaultimpl;
import com.ctrip.framework.apollo.portal.entity.bo.Email;
import com.ctrip.framework.apollo.portal.spi.EmailService;
public class DefaultEmailService implements EmailService{
@Override
public void send(Email email){
//do nothing
}
}
package com.ctrip.framework.apollo.portal.spi.defaultimpl;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
/**
* 不是ctrip的公司默认提供一个假用户
......
......@@ -2,7 +2,7 @@ package com.ctrip.framework.apollo.portal.spi.defaultimpl;
import com.google.common.collect.Lists;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.spi.UserService;
import java.util.Arrays;
......
......@@ -19,7 +19,7 @@ public class RelativeDateFormat {
public static String format(Date date) {
if (date.after(new Date())) {
throw new IllegalArgumentException("To format date can not after now");
return "now";
}
long delta = new Date().getTime() - date.getTime();
......
ctrip:
appid: 100003173
email:
send:
code: 37030033
template:
id: 37030033
survival:
duration: 5
......@@ -4,9 +4,6 @@ spring:
profiles:
active: ${apollo_profile}
ctrip:
appid: 100003173
server:
port: 8080
......
......@@ -41,6 +41,8 @@ function releaseModalDirective(toastr, AppUtil, EventManager, ReleaseService, Na
function release() {
if (scope.toReleaseNamespace.mergeAndPublish) {
mergeAndPublish();
} else if (scope.toReleaseNamespace.isBranch) {
grayPublish();
} else {
publish();
}
......@@ -49,7 +51,7 @@ function releaseModalDirective(toastr, AppUtil, EventManager, ReleaseService, Na
function publish() {
scope.releaseBtnDisabled = true;
ReleaseService.release(scope.appId, scope.env,
ReleaseService.publish(scope.appId, scope.env,
scope.toReleaseNamespace.baseInfo.clusterName,
scope.toReleaseNamespace.baseInfo.namespaceName,
scope.toReleaseNamespace.releaseTitle,
......@@ -57,38 +59,13 @@ function releaseModalDirective(toastr, AppUtil, EventManager, ReleaseService, Na
function (result) {
AppUtil.hideModal('#releaseModal');
toastr.success("发布成功");
//refresh all namespace items
scope.releaseBtnDisabled = false;
//gray release
if (scope.toReleaseNamespace.isBranch
&& !scope.toReleaseNamespace.mergeAndPublish) {
//refresh item status
scope.toReleaseNamespace.branchItems.forEach(function (item, index) {
if (item.isDeleted) {
scope.toReleaseNamespace.branchItems.splice(index, 1);
} else {
item.isModified = false;
}
});
scope.toReleaseNamespace.itemModifiedCnt = 0;
//check rules
if (!scope.toReleaseNamespace.rules
|| !scope.toReleaseNamespace.rules.ruleItems
|| !scope.toReleaseNamespace.rules.ruleItems.length) {
scope.toReleaseNamespace.viewType = 'rule';
AppUtil.showModal('#grayReleaseWithoutRulesTips');
}
scope.releaseBtnDisabled = false;
} else {
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{
namespace: scope.toReleaseNamespace
})
}
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE,
{
namespace: scope.toReleaseNamespace
})
}, function (result) {
scope.releaseBtnDisabled = false;
......@@ -99,6 +76,46 @@ function releaseModalDirective(toastr, AppUtil, EventManager, ReleaseService, Na
}
function grayPublish() {
scope.releaseBtnDisabled = true;
ReleaseService.grayPublish(scope.appId, scope.env,
scope.toReleaseNamespace.parentNamespace.baseInfo.clusterName,
scope.toReleaseNamespace.baseInfo.namespaceName,
scope.toReleaseNamespace.baseInfo.clusterName,
scope.toReleaseNamespace.releaseTitle,
scope.releaseComment).then(
function (result) {
AppUtil.hideModal('#releaseModal');
toastr.success("灰度发布成功");
scope.releaseBtnDisabled = false;
//refresh item status
scope.toReleaseNamespace.branchItems.forEach(function (item, index) {
if (item.isDeleted) {
scope.toReleaseNamespace.branchItems.splice(index, 1);
} else {
item.isModified = false;
}
});
scope.toReleaseNamespace.itemModifiedCnt = 0;
//check rules
if (!scope.toReleaseNamespace.rules
|| !scope.toReleaseNamespace.rules.ruleItems
|| !scope.toReleaseNamespace.rules.ruleItems.length) {
scope.toReleaseNamespace.viewType = 'rule';
AppUtil.showModal('#grayReleaseWithoutRulesTips');
}
}, function (result) {
scope.releaseBtnDisabled = false;
toastr.error(AppUtil.errorMsg(result), "灰度发布失败");
});
}
function mergeAndPublish() {
NamespaceBranchService.mergeAndReleaseBranch(scope.appId,
......
......@@ -16,7 +16,11 @@ appService.service('ReleaseService', ['$resource', '$q', function ($resource, $q
},
release: {
method: 'POST',
url: '/apps/:appId/envs/:env/clusters/:clusterName/namespaces/:namespaceName/release'
url: '/apps/:appId/envs/:env/clusters/:clusterName/namespaces/:namespaceName/releases'
},
gray_release: {
method: 'POST',
url: '/apps/:appId/envs/:env/clusters/:clusterName/namespaces/:namespaceName/branches/:branchName/releases'
},
rollback: {
method: 'PUT',
......@@ -42,6 +46,25 @@ appService.service('ReleaseService', ['$resource', '$q', function ($resource, $q
return d.promise;
}
function createGrayRelease(appId, env, clusterName, namespaceName, branchName, releaseTitle, comment) {
var d = $q.defer();
resource.gray_release({
appId: appId,
env: env,
clusterName: clusterName,
namespaceName: namespaceName,
branchName:branchName
}, {
releaseTitle: releaseTitle,
releaseComment: comment
}, function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
});
return d.promise;
}
function findAllReleases(appId, env, clusterName, namespaceName, page, size) {
var d = $q.defer();
resource.find_all_releases({
......@@ -106,7 +129,8 @@ appService.service('ReleaseService', ['$resource', '$q', function ($resource, $q
}
return {
release: createRelease,
publish: createRelease,
grayPublish: createGrayRelease,
findAllRelease: findAllReleases,
findActiveReleases: findActiveReleases,
compare: compare,
......
<section class="panel namespace-panel">
<!--public or link label-->
<header class="row namespace-attribute-panel">
<div class="text-center namespace-attribute-public">
......
......@@ -52,8 +52,9 @@ public class RetryableRestTemplateTest extends AbstractUnitTest {
@Before
public void init() {
socketTimeoutException.initCause(new SocketTimeoutException());
httpHostConnectException
.initCause(new HttpHostConnectException(new HttpHost(serviceOne, 80), new ConnectException()));
.initCause(new HttpHostConnectException(new ConnectTimeoutException(), new HttpHost(serviceOne, 80)));
connectTimeoutException.initCause(new ConnectTimeoutException());
}
......
......@@ -2,8 +2,8 @@ package com.ctrip.framework.apollo.portal.controller;
import com.ctrip.framework.apollo.openapi.entity.ConsumerToken;
import com.ctrip.framework.apollo.openapi.service.ConsumerService;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import org.junit.Before;
import org.junit.Test;
......
......@@ -7,12 +7,12 @@ import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.api.AdminServiceAPI;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.components.txtresolver.PropertyResolver;
import com.ctrip.framework.apollo.portal.entity.model.NamespaceTextModel;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.vo.ItemDiffs;
import com.ctrip.framework.apollo.portal.entity.vo.NamespaceIdentifier;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import org.junit.Assert;
import org.junit.Before;
......
......@@ -7,7 +7,7 @@ import com.ctrip.framework.apollo.portal.AbstractUnitTest;
import com.ctrip.framework.apollo.portal.constant.PermissionType;
import com.ctrip.framework.apollo.portal.entity.po.Permission;
import com.ctrip.framework.apollo.portal.entity.po.Role;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.util.RoleUtils;
......
......@@ -8,7 +8,7 @@ import com.ctrip.framework.apollo.portal.AbstractIntegrationTest;
import com.ctrip.framework.apollo.portal.entity.po.Permission;
import com.ctrip.framework.apollo.portal.entity.po.Role;
import com.ctrip.framework.apollo.portal.entity.po.RolePermission;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.entity.po.UserRole;
import com.ctrip.framework.apollo.portal.repository.PermissionRepository;
import com.ctrip.framework.apollo.portal.repository.RolePermissionRepository;
......
......@@ -4,7 +4,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.ctrip.framework.apollo.portal.AbstractUnitTest;
import com.ctrip.framework.apollo.portal.entity.po.UserInfo;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.service.ServerConfigService;
import org.junit.Before;
......
......@@ -8,11 +8,8 @@ spring:
logging:
level:
org.springframework.cloud: 'DEBUG'
file: /opt/logs/${ctrip.appid}/apollo-portal.log
file: /opt/logs/100003173/apollo-portal.log
ctrip:
appid: 100003173
apollo:
portal:
envs: local
......
......@@ -186,6 +186,11 @@
<artifactId>apollo-sso-ctrip</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo-ctrip-service</groupId>
<artifactId>apollo-email-service</artifactId>
<version>1.0.0</version>
</dependency>
<!--third party -->
<dependency>
<groupId>mysql</groupId>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册