Commit d23e60e1 authored by Jason Song's avatar Jason Song Committed by GitHub

Merge pull request #1276 from nobodyiam/delete-app-api

add delete app api
parents 6860f0a2 2d9ece83
...@@ -54,7 +54,7 @@ public class AppController { ...@@ -54,7 +54,7 @@ public class AppController {
if (entity == null) { if (entity == null) {
throw new NotFoundException("app not found for appId " + appId); throw new NotFoundException("app not found for appId " + appId);
} }
appService.delete(entity.getId(), operator); adminService.deleteApp(entity, operator);
} }
@RequestMapping(value = "/apps/{appId:.+}", method = RequestMethod.PUT) @RequestMapping(value = "/apps/{appId:.+}", method = RequestMethod.PUT)
...@@ -91,5 +91,4 @@ public class AppController { ...@@ -91,5 +91,4 @@ public class AppController {
public boolean isAppIdUnique(@PathVariable("appId") String appId) { public boolean isAppIdUnique(@PathVariable("appId") String appId) {
return appService.isAppIdUnique(appId); return appService.isAppIdUnique(appId);
} }
} }
...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.biz.repository; ...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.biz.repository;
import com.ctrip.framework.apollo.common.entity.AppNamespace; import com.ctrip.framework.apollo.common.entity.AppNamespace;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.List; import java.util.List;
...@@ -24,4 +26,7 @@ public interface AppNamespaceRepository extends PagingAndSortingRepository<AppNa ...@@ -24,4 +26,7 @@ public interface AppNamespaceRepository extends PagingAndSortingRepository<AppNa
List<AppNamespace> findFirst500ByIdGreaterThanOrderByIdAsc(long id); List<AppNamespace> findFirst500ByIdGreaterThanOrderByIdAsc(long id);
@Modifying
@Query("UPDATE AppNamespace SET IsDeleted=1,DataChange_LastModifiedBy = ?2 WHERE AppId=?1")
int batchDeleteByAppId(String appId, String operator);
} }
...@@ -14,5 +14,4 @@ public interface AppRepository extends PagingAndSortingRepository<App, Long> { ...@@ -14,5 +14,4 @@ public interface AppRepository extends PagingAndSortingRepository<App, Long> {
List<App> findByName(@Param("name") String name); List<App> findByName(@Param("name") String name);
App findByAppId(String appId); App findByAppId(String appId);
} }
...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.biz.repository; ...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.biz.repository;
import com.ctrip.framework.apollo.biz.entity.GrayReleaseRule; import com.ctrip.framework.apollo.biz.entity.GrayReleaseRule;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.List; import java.util.List;
...@@ -17,4 +19,7 @@ public interface GrayReleaseRuleRepository extends PagingAndSortingRepository<Gr ...@@ -17,4 +19,7 @@ public interface GrayReleaseRuleRepository extends PagingAndSortingRepository<Gr
List<GrayReleaseRule> findFirst500ByIdGreaterThanOrderByIdAsc(Long id); List<GrayReleaseRule> findFirst500ByIdGreaterThanOrderByIdAsc(Long id);
@Modifying
@Query("UPDATE GrayReleaseRule SET IsDeleted=1, DataChange_LastModifiedBy = ?4 where appId=?1 and clusterName=?2 and namespaceName = ?3")
int batchDelete(String appId, String clusterName, String namespaceName, String operator);
} }
package com.ctrip.framework.apollo.biz.service; package com.ctrip.framework.apollo.biz.service;
import com.ctrip.framework.apollo.biz.entity.Cluster;
import com.ctrip.framework.apollo.common.entity.App; import com.ctrip.framework.apollo.common.entity.App;
import com.ctrip.framework.apollo.common.exception.NotFoundException;
import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.ConfigConsts;
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.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
@Service @Service
public class AdminService { public class AdminService {
...@@ -19,6 +26,8 @@ public class AdminService { ...@@ -19,6 +26,8 @@ public class AdminService {
@Autowired @Autowired
private NamespaceService namespaceService; private NamespaceService namespaceService;
private final static Logger logger = LoggerFactory.getLogger(AdminService.class);
@Transactional @Transactional
public App createNewApp(App app) { public App createNewApp(App app) {
String createBy = app.getDataChangeCreatedBy(); String createBy = app.getDataChangeCreatedBy();
...@@ -35,5 +44,25 @@ public class AdminService { ...@@ -35,5 +44,25 @@ public class AdminService {
return app; return app;
} }
@Transactional
public void deleteApp(App app, String operator) {
String appId = app.getAppId();
logger.info("{} is deleting App:{}", operator, appId);
List<Cluster> managedClusters = clusterService.findClusters(appId);
// 1. delete clusters
if (Objects.nonNull(managedClusters)) {
for (Cluster cluster : managedClusters) {
clusterService.delete(cluster.getId(), operator);
}
}
// 2. delete appNamespace
appNamespaceService.batchDelete(appId, operator);
// 3. delete app
appService.delete(app.getId(), operator);
}
} }
...@@ -137,4 +137,9 @@ public class AppNamespaceService { ...@@ -137,4 +137,9 @@ public class AppNamespaceService {
namespaceService.save(namespace); namespaceService.save(namespace);
} }
} }
@Transactional
public void batchDelete(String appId, String operator) {
appNamespaceRepository.batchDeleteByAppId(appId, operator);
}
} }
...@@ -137,4 +137,7 @@ public class ClusterService { ...@@ -137,4 +137,7 @@ public class ClusterService {
return clusterRepository.findByParentClusterId(parentCluster.getId()); return clusterRepository.findByParentClusterId(parentCluster.getId());
} }
public List<Cluster> findClusters(String appId) {
return clusterRepository.findByAppId(appId);
}
} }
package com.ctrip.framework.apollo.biz.service;
import com.ctrip.framework.apollo.biz.repository.GrayReleaseRuleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class GrayReleaseRuleService {
@Autowired
private GrayReleaseRuleRepository grayReleaseRuleRepository;
@Transactional
public void batchDelete(String appId, String clusterName, String namespaceName, String operator) {
grayReleaseRuleRepository.batchDelete(appId, clusterName, namespaceName, operator);
}
}
...@@ -59,6 +59,8 @@ public class NamespaceService { ...@@ -59,6 +59,8 @@ public class NamespaceService {
@Autowired @Autowired
private ReleaseHistoryService releaseHistoryService; private ReleaseHistoryService releaseHistoryService;
@Autowired @Autowired
private GrayReleaseRuleService grayReleaseRuleService;
@Autowired
private NamespaceLockService namespaceLockService; private NamespaceLockService namespaceLockService;
@Autowired @Autowired
private InstanceService instanceService; private InstanceService instanceService;
...@@ -263,17 +265,18 @@ public class NamespaceService { ...@@ -263,17 +265,18 @@ public class NamespaceService {
itemService.batchDelete(namespace.getId(), operator); itemService.batchDelete(namespace.getId(), operator);
commitService.batchDelete(appId, clusterName, namespace.getNamespaceName(), operator); commitService.batchDelete(appId, clusterName, namespace.getNamespaceName(), operator);
if (!isChildNamespace(namespace)) { releaseService.batchDelete(appId, clusterName, namespace.getNamespaceName(), operator);
releaseService.batchDelete(appId, clusterName, namespace.getNamespaceName(), operator); grayReleaseRuleService.batchDelete(appId, clusterName, namespace.getNamespaceName(), operator);
}
//delete child namespace if (!isChildNamespace(namespace)) {
Namespace childNamespace = findChildNamespace(namespace); //delete child namespace
if (childNamespace != null) { Namespace childNamespace = findChildNamespace(namespace);
namespaceBranchService.deleteBranch(appId, clusterName, namespaceName, if (childNamespace != null) {
childNamespace.getClusterName(), NamespaceBranchStatus.DELETED, operator); namespaceBranchService.deleteBranch(appId, clusterName, namespaceName,
//delete child namespace's releases. Notice: delete child namespace will not delete child namespace's releases childNamespace.getClusterName(), NamespaceBranchStatus.DELETED, operator);
releaseService.batchDelete(appId, childNamespace.getClusterName(), namespaceName, operator); //delete child namespace's releases. Notice: delete child namespace will not delete child namespace's releases
releaseService.batchDelete(appId, childNamespace.getClusterName(), namespaceName, operator);
}
} }
releaseHistoryService.batchDelete(appId, clusterName, namespaceName, operator); releaseHistoryService.batchDelete(appId, clusterName, namespaceName, operator);
...@@ -394,6 +397,4 @@ public class NamespaceService { ...@@ -394,6 +397,4 @@ public class NamespaceService {
return false; return false;
} }
} }
...@@ -8,15 +8,13 @@ import com.ctrip.framework.apollo.biz.repository.AppRepository; ...@@ -8,15 +8,13 @@ import com.ctrip.framework.apollo.biz.repository.AppRepository;
import com.ctrip.framework.apollo.common.entity.App; import com.ctrip.framework.apollo.common.entity.App;
import com.ctrip.framework.apollo.common.exception.ServiceException; import com.ctrip.framework.apollo.common.exception.ServiceException;
import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.ConfigConsts;
import java.util.Date;
import java.util.List;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date; public class AdminServiceTest extends AbstractIntegrationTest {
import java.util.List;
public class AdminServiceTest extends AbstractIntegrationTest{
@Autowired @Autowired
private AdminService adminService; private AdminService adminService;
...@@ -33,6 +31,9 @@ public class AdminServiceTest extends AbstractIntegrationTest{ ...@@ -33,6 +31,9 @@ public class AdminServiceTest extends AbstractIntegrationTest{
@Autowired @Autowired
private NamespaceService namespaceService; private NamespaceService namespaceService;
@Autowired
private AppNamespaceService appNamespaceService;
@Test @Test
public void testCreateNewApp() { public void testCreateNewApp() {
String appId = "someAppId"; String appId = "someAppId";
...@@ -79,4 +80,37 @@ public class AdminServiceTest extends AbstractIntegrationTest{ ...@@ -79,4 +80,37 @@ public class AdminServiceTest extends AbstractIntegrationTest{
adminService.createNewApp(app); adminService.createNewApp(app);
} }
@Test
public void testDeleteApp() {
String appId = "someAppId";
App app = new App();
app.setAppId(appId);
app.setName("someAppName");
String owner = "someOwnerName";
app.setOwnerName(owner);
app.setOwnerEmail("someOwnerName@ctrip.com");
app.setDataChangeCreatedBy(owner);
app.setDataChangeLastModifiedBy(owner);
app.setDataChangeCreatedTime(new Date());
app = adminService.createNewApp(app);
Assert.assertEquals(appId, app.getAppId());
Assert.assertEquals(1, appNamespaceService.findByAppId(appId).size());
Assert.assertEquals(1, clusterService.findClusters(appId).size());
Assert.assertEquals(1, namespaceService.findNamespaces(appId, ConfigConsts.CLUSTER_NAME_DEFAULT).size());
adminService.deleteApp(app, owner);
Assert.assertEquals(0, appNamespaceService.findByAppId(appId).size());
Assert.assertEquals(0, clusterService.findClusters(appId).size());
Assert
.assertEquals(0, namespaceService.findByAppIdAndNamespaceName(appId, ConfigConsts.CLUSTER_NAME_DEFAULT).size());
}
} }
...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.openapi.repository; ...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.openapi.repository;
import com.ctrip.framework.apollo.openapi.entity.ConsumerRole; import com.ctrip.framework.apollo.openapi.entity.ConsumerRole;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.List; import java.util.List;
...@@ -23,4 +25,8 @@ public interface ConsumerRoleRepository extends PagingAndSortingRepository<Consu ...@@ -23,4 +25,8 @@ public interface ConsumerRoleRepository extends PagingAndSortingRepository<Consu
List<ConsumerRole> findByRoleId(long roleId); List<ConsumerRole> findByRoleId(long roleId);
ConsumerRole findByConsumerIdAndRoleId(long consumerId, long roleId); ConsumerRole findByConsumerIdAndRoleId(long consumerId, long roleId);
@Modifying
@Query("UPDATE ConsumerRole SET IsDeleted=1, DataChange_LastModifiedBy = ?2 WHERE RoleId in ?1")
Integer batchDeleteByRoleIds(List<Long> roleIds, String operator);
} }
package com.ctrip.framework.apollo.portal.api; package com.ctrip.framework.apollo.portal.api;
import com.google.common.base.Joiner;
import com.ctrip.framework.apollo.common.dto.AppDTO; import com.ctrip.framework.apollo.common.dto.AppDTO;
import com.ctrip.framework.apollo.common.dto.AppNamespaceDTO; import com.ctrip.framework.apollo.common.dto.AppNamespaceDTO;
import com.ctrip.framework.apollo.common.dto.ClusterDTO; import com.ctrip.framework.apollo.common.dto.ClusterDTO;
...@@ -17,7 +15,12 @@ import com.ctrip.framework.apollo.common.dto.PageDTO; ...@@ -17,7 +15,12 @@ import com.ctrip.framework.apollo.common.dto.PageDTO;
import com.ctrip.framework.apollo.common.dto.ReleaseDTO; import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
import com.ctrip.framework.apollo.common.dto.ReleaseHistoryDTO; import com.ctrip.framework.apollo.common.dto.ReleaseHistoryDTO;
import com.ctrip.framework.apollo.core.enums.Env; import com.ctrip.framework.apollo.core.enums.Env;
import com.google.common.base.Joiner;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Health;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
...@@ -29,12 +32,6 @@ import org.springframework.util.CollectionUtils; ...@@ -29,12 +32,6 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Service @Service
public class AdminServiceAPI { public class AdminServiceAPI {
...@@ -61,6 +58,10 @@ public class AdminServiceAPI { ...@@ -61,6 +58,10 @@ public class AdminServiceAPI {
public void updateApp(Env env, AppDTO app) { public void updateApp(Env env, AppDTO app) {
restTemplate.put(env, "apps/{appId}", app, app.getAppId()); restTemplate.put(env, "apps/{appId}", app, app.getAppId());
} }
public void deleteApp(Env env, String appId, String operator) {
restTemplate.delete(env, "/apps/{appId}?operator={operator}", appId, operator);
}
} }
...@@ -73,30 +74,30 @@ public class AdminServiceAPI { ...@@ -73,30 +74,30 @@ public class AdminServiceAPI {
public List<NamespaceDTO> findNamespaceByCluster(String appId, Env env, String clusterName) { public List<NamespaceDTO> findNamespaceByCluster(String appId, Env env, String clusterName) {
NamespaceDTO[] namespaceDTOs = restTemplate.get(env, "apps/{appId}/clusters/{clusterName}/namespaces", NamespaceDTO[] namespaceDTOs = restTemplate.get(env, "apps/{appId}/clusters/{clusterName}/namespaces",
NamespaceDTO[].class, appId, NamespaceDTO[].class, appId,
clusterName); clusterName);
return Arrays.asList(namespaceDTOs); return Arrays.asList(namespaceDTOs);
} }
public NamespaceDTO loadNamespace(String appId, Env env, String clusterName, public NamespaceDTO loadNamespace(String appId, Env env, String clusterName,
String namespaceName) { String namespaceName) {
return return
restTemplate.get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}", restTemplate.get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}",
NamespaceDTO.class, appId, clusterName, namespaceName); NamespaceDTO.class, appId, clusterName, namespaceName);
} }
public NamespaceDTO findPublicNamespaceForAssociatedNamespace(Env env, String appId, String clusterName, public NamespaceDTO findPublicNamespaceForAssociatedNamespace(Env env, String appId, String clusterName,
String namespaceName) { String namespaceName) {
return return
restTemplate restTemplate
.get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/associated-public-namespace", .get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/associated-public-namespace",
NamespaceDTO.class, appId, clusterName, namespaceName); NamespaceDTO.class, appId, clusterName, namespaceName);
} }
public NamespaceDTO createNamespace(Env env, NamespaceDTO namespace) { public NamespaceDTO createNamespace(Env env, NamespaceDTO namespace) {
return restTemplate return restTemplate
.post(env, "apps/{appId}/clusters/{clusterName}/namespaces", namespace, NamespaceDTO.class, .post(env, "apps/{appId}/clusters/{clusterName}/namespaces", namespace, NamespaceDTO.class,
namespace.getAppId(), namespace.getClusterName()); namespace.getAppId(), namespace.getClusterName());
} }
public AppNamespaceDTO createAppNamespace(Env env, AppNamespaceDTO appNamespace) { public AppNamespaceDTO createAppNamespace(Env env, AppNamespaceDTO appNamespace) {
...@@ -107,8 +108,8 @@ public class AdminServiceAPI { ...@@ -107,8 +108,8 @@ public class AdminServiceAPI {
public void deleteNamespace(Env env, String appId, String clusterName, String namespaceName, String operator) { public void deleteNamespace(Env env, String appId, String clusterName, String namespaceName, String operator) {
restTemplate restTemplate
.delete(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}?operator={operator}", appId, .delete(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}?operator={operator}", appId,
clusterName, clusterName,
namespaceName, operator); namespaceName, operator);
} }
public Map<String, Boolean> getNamespacePublishInfo(Env env, String appId) { public Map<String, Boolean> getNamespacePublishInfo(Env env, String appId) {
...@@ -116,17 +117,17 @@ public class AdminServiceAPI { ...@@ -116,17 +117,17 @@ public class AdminServiceAPI {
} }
public List<NamespaceDTO> getPublicAppNamespaceAllNamespaces(Env env, String publicNamespaceName, public List<NamespaceDTO> getPublicAppNamespaceAllNamespaces(Env env, String publicNamespaceName,
int page, int size) { int page, int size) {
NamespaceDTO[] namespaceDTOs = NamespaceDTO[] namespaceDTOs =
restTemplate.get(env, "/appnamespaces/{publicNamespaceName}/namespaces?page={page}&size={size}", restTemplate.get(env, "/appnamespaces/{publicNamespaceName}/namespaces?page={page}&size={size}",
NamespaceDTO[].class, publicNamespaceName, page, size); NamespaceDTO[].class, publicNamespaceName, page, size);
return Arrays.asList(namespaceDTOs); return Arrays.asList(namespaceDTOs);
} }
public int countPublicAppNamespaceAssociatedNamespaces(Env env, String publicNamesapceName) { public int countPublicAppNamespaceAssociatedNamespaces(Env env, String publicNamesapceName) {
Integer count = Integer count =
restTemplate.get(env, "/appnamespaces/{publicNamespaceName}/associated-namespaces/count", Integer.class, restTemplate.get(env, "/appnamespaces/{publicNamespaceName}/associated-namespaces/count", Integer.class,
publicNamesapceName); publicNamesapceName);
return count == null ? 0 : count; return count == null ? 0 : count;
} }
...@@ -139,30 +140,30 @@ public class AdminServiceAPI { ...@@ -139,30 +140,30 @@ public class AdminServiceAPI {
public List<ItemDTO> findItems(String appId, Env env, String clusterName, String namespaceName) { public List<ItemDTO> findItems(String appId, Env env, String clusterName, String namespaceName) {
ItemDTO[] itemDTOs = ItemDTO[] itemDTOs =
restTemplate.get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items", restTemplate.get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items",
ItemDTO[].class, appId, clusterName, namespaceName); ItemDTO[].class, appId, clusterName, namespaceName);
return Arrays.asList(itemDTOs); return Arrays.asList(itemDTOs);
} }
public ItemDTO loadItem(Env env, String appId, String clusterName, String namespaceName, String key) { public ItemDTO loadItem(Env env, String appId, String clusterName, String namespaceName, String key) {
return restTemplate.get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{key}", return restTemplate.get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{key}",
ItemDTO.class, appId, clusterName, namespaceName, key); ItemDTO.class, appId, clusterName, namespaceName, key);
} }
public void updateItemsByChangeSet(String appId, Env env, String clusterName, String namespace, public void updateItemsByChangeSet(String appId, Env env, String clusterName, String namespace,
ItemChangeSets changeSets) { ItemChangeSets changeSets) {
restTemplate.post(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/itemset", restTemplate.post(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/itemset",
changeSets, Void.class, appId, clusterName, namespace); changeSets, Void.class, appId, clusterName, namespace);
} }
public void updateItem(String appId, Env env, String clusterName, String namespace, long itemId, ItemDTO item) { public void updateItem(String appId, Env env, String clusterName, String namespace, long itemId, ItemDTO item) {
restTemplate.put(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{itemId}", restTemplate.put(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{itemId}",
item, appId, clusterName, namespace, itemId); item, appId, clusterName, namespace, itemId);
} }
public ItemDTO createItem(String appId, Env env, String clusterName, String namespace, ItemDTO item) { public ItemDTO createItem(String appId, Env env, String clusterName, String namespace, ItemDTO item) {
return restTemplate.post(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items", return restTemplate.post(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items",
item, ItemDTO.class, appId, clusterName, namespace); item, ItemDTO.class, appId, clusterName, namespace);
} }
public void deleteItem(Env env, long itemId, String operator) { public void deleteItem(Env env, long itemId, String operator) {
...@@ -176,25 +177,25 @@ public class AdminServiceAPI { ...@@ -176,25 +177,25 @@ public class AdminServiceAPI {
public List<ClusterDTO> findClustersByApp(String appId, Env env) { public List<ClusterDTO> findClustersByApp(String appId, Env env) {
ClusterDTO[] clusterDTOs = restTemplate.get(env, "apps/{appId}/clusters", ClusterDTO[].class, ClusterDTO[] clusterDTOs = restTemplate.get(env, "apps/{appId}/clusters", ClusterDTO[].class,
appId); appId);
return Arrays.asList(clusterDTOs); return Arrays.asList(clusterDTOs);
} }
public ClusterDTO loadCluster(String appId, Env env, String clusterName) { public ClusterDTO loadCluster(String appId, Env env, String clusterName) {
return restTemplate.get(env, "apps/{appId}/clusters/{clusterName}", ClusterDTO.class, return restTemplate.get(env, "apps/{appId}/clusters/{clusterName}", ClusterDTO.class,
appId, clusterName); appId, clusterName);
} }
public boolean isClusterUnique(String appId, Env env, String clusterName) { public boolean isClusterUnique(String appId, Env env, String clusterName) {
return restTemplate return restTemplate
.get(env, "apps/{appId}/cluster/{clusterName}/unique", Boolean.class, .get(env, "apps/{appId}/cluster/{clusterName}/unique", Boolean.class,
appId, clusterName); appId, clusterName);
} }
public ClusterDTO create(Env env, ClusterDTO cluster) { public ClusterDTO create(Env env, ClusterDTO cluster) {
return restTemplate.post(env, "apps/{appId}/clusters", cluster, ClusterDTO.class, return restTemplate.post(env, "apps/{appId}/clusters", cluster, ClusterDTO.class,
cluster.getAppId()); cluster.getAppId());
} }
...@@ -225,7 +226,7 @@ public class AdminServiceAPI { ...@@ -225,7 +226,7 @@ public class AdminServiceAPI {
} }
public List<ReleaseDTO> findAllReleases(String appId, Env env, String clusterName, String namespaceName, int page, public List<ReleaseDTO> findAllReleases(String appId, Env env, String clusterName, String namespaceName, int page,
int size) { int size) {
ReleaseDTO[] releaseDTOs = restTemplate.get( ReleaseDTO[] releaseDTOs = restTemplate.get(
env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/all?page={page}&size={size}", env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/all?page={page}&size={size}",
ReleaseDTO[].class, ReleaseDTO[].class,
...@@ -234,8 +235,8 @@ public class AdminServiceAPI { ...@@ -234,8 +235,8 @@ public class AdminServiceAPI {
} }
public List<ReleaseDTO> findActiveReleases(String appId, Env env, String clusterName, String namespaceName, public List<ReleaseDTO> findActiveReleases(String appId, Env env, String clusterName, String namespaceName,
int page, int page,
int size) { int size) {
ReleaseDTO[] releaseDTOs = restTemplate.get( ReleaseDTO[] releaseDTOs = restTemplate.get(
env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/active?page={page}&size={size}", env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/active?page={page}&size={size}",
ReleaseDTO[].class, ReleaseDTO[].class,
...@@ -244,16 +245,16 @@ public class AdminServiceAPI { ...@@ -244,16 +245,16 @@ public class AdminServiceAPI {
} }
public ReleaseDTO loadLatestRelease(String appId, Env env, String clusterName, public ReleaseDTO loadLatestRelease(String appId, Env env, String clusterName,
String namespace) { String namespace) {
ReleaseDTO releaseDTO = restTemplate ReleaseDTO releaseDTO = restTemplate
.get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/latest", .get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/latest",
ReleaseDTO.class, appId, clusterName, namespace); ReleaseDTO.class, appId, clusterName, namespace);
return releaseDTO; return releaseDTO;
} }
public ReleaseDTO createRelease(String appId, Env env, String clusterName, String namespace, public ReleaseDTO createRelease(String appId, Env env, String clusterName, String namespace,
String releaseName, String releaseComment, String operator, String releaseName, String releaseComment, String operator,
boolean isEmergencyPublish) { boolean isEmergencyPublish) {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); headers.setContentType(MediaType.parseMediaType(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"));
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(); MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
...@@ -270,22 +271,22 @@ public class AdminServiceAPI { ...@@ -270,22 +271,22 @@ public class AdminServiceAPI {
} }
public ReleaseDTO updateAndPublish(String appId, Env env, String clusterName, String namespace, public ReleaseDTO updateAndPublish(String appId, Env env, String clusterName, String namespace,
String releaseName, String releaseComment, String branchName, String releaseName, String releaseComment, String branchName,
boolean isEmergencyPublish, boolean deleteBranch, ItemChangeSets changeSets) { boolean isEmergencyPublish, boolean deleteBranch, ItemChangeSets changeSets) {
return restTemplate.post(env, return restTemplate.post(env,
"apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/updateAndPublish?" "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/updateAndPublish?"
+ "releaseName={releaseName}&releaseComment={releaseComment}&branchName={branchName}" + "releaseName={releaseName}&releaseComment={releaseComment}&branchName={branchName}"
+ "&deleteBranch={deleteBranch}&isEmergencyPublish={isEmergencyPublish}", + "&deleteBranch={deleteBranch}&isEmergencyPublish={isEmergencyPublish}",
changeSets, ReleaseDTO.class, appId, clusterName, namespace, changeSets, ReleaseDTO.class, appId, clusterName, namespace,
releaseName, releaseComment, branchName, deleteBranch, isEmergencyPublish); releaseName, releaseComment, branchName, deleteBranch, isEmergencyPublish);
} }
public void rollback(Env env, long releaseId, String operator) { public void rollback(Env env, long releaseId, String operator) {
restTemplate.put(env, restTemplate.put(env,
"releases/{releaseId}/rollback?operator={operator}", "releases/{releaseId}/rollback?operator={operator}",
null, releaseId, operator); null, releaseId, operator);
} }
} }
...@@ -295,9 +296,9 @@ public class AdminServiceAPI { ...@@ -295,9 +296,9 @@ public class AdminServiceAPI {
public List<CommitDTO> find(String appId, Env env, String clusterName, String namespaceName, int page, int size) { public List<CommitDTO> find(String appId, Env env, String clusterName, String namespaceName, int page, int size) {
CommitDTO[] commitDTOs = restTemplate.get(env, CommitDTO[] commitDTOs = restTemplate.get(env,
"apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/commit?page={page}&size={size}", "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/commit?page={page}&size={size}",
CommitDTO[].class, CommitDTO[].class,
appId, clusterName, namespaceName, page, size); appId, clusterName, namespaceName, page, size);
return Arrays.asList(commitDTOs); return Arrays.asList(commitDTOs);
} }
...@@ -308,8 +309,8 @@ public class AdminServiceAPI { ...@@ -308,8 +309,8 @@ public class AdminServiceAPI {
public NamespaceLockDTO getNamespaceLockOwner(String appId, Env env, String clusterName, String namespaceName) { public NamespaceLockDTO getNamespaceLockOwner(String appId, Env env, String clusterName, String namespaceName) {
return restTemplate.get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/lock", return restTemplate.get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/lock",
NamespaceLockDTO.class, NamespaceLockDTO.class,
appId, clusterName, namespaceName); appId, clusterName, namespaceName);
} }
} }
...@@ -328,33 +329,33 @@ public class AdminServiceAPI { ...@@ -328,33 +329,33 @@ public class AdminServiceAPI {
entity = entity =
restTemplate restTemplate
.get(env, "/instances/by-release?releaseId={releaseId}&page={page}&size={size}", pageInstanceDtoType, .get(env, "/instances/by-release?releaseId={releaseId}&page={page}&size={size}", pageInstanceDtoType,
releaseId, page, size); releaseId, page, size);
return entity.getBody(); return entity.getBody();
} }
public List<InstanceDTO> getByReleasesNotIn(String appId, Env env, String clusterName, String namespaceName, public List<InstanceDTO> getByReleasesNotIn(String appId, Env env, String clusterName, String namespaceName,
Set<Long> releaseIds) { Set<Long> releaseIds) {
InstanceDTO[] InstanceDTO[]
instanceDTOs = instanceDTOs =
restTemplate.get(env, restTemplate.get(env,
"/instances/by-namespace-and-releases-not-in?appId={appId}&clusterName={clusterName}&namespaceName={namespaceName}&releaseIds={releaseIds}", "/instances/by-namespace-and-releases-not-in?appId={appId}&clusterName={clusterName}&namespaceName={namespaceName}&releaseIds={releaseIds}",
InstanceDTO[].class, appId, clusterName, namespaceName, joiner.join(releaseIds)); InstanceDTO[].class, appId, clusterName, namespaceName, joiner.join(releaseIds));
return Arrays.asList(instanceDTOs); return Arrays.asList(instanceDTOs);
} }
public PageDTO<InstanceDTO> getByNamespace(String appId, Env env, String clusterName, String namespaceName, public PageDTO<InstanceDTO> getByNamespace(String appId, Env env, String clusterName, String namespaceName,
String instanceAppId, String instanceAppId,
int page, int size) { int page, int size) {
ResponseEntity<PageDTO<InstanceDTO>> ResponseEntity<PageDTO<InstanceDTO>>
entity = entity =
restTemplate.get(env, restTemplate.get(env,
"/instances/by-namespace?appId={appId}" "/instances/by-namespace?appId={appId}"
+ "&clusterName={clusterName}&namespaceName={namespaceName}&instanceAppId={instanceAppId}" + "&clusterName={clusterName}&namespaceName={namespaceName}&instanceAppId={instanceAppId}"
+ "&page={page}&size={size}", + "&page={page}&size={size}",
pageInstanceDtoType, appId, clusterName, namespaceName, instanceAppId, page, size); pageInstanceDtoType, appId, clusterName, namespaceName, instanceAppId, page, size);
return entity.getBody(); return entity.getBody();
} }
...@@ -362,8 +363,8 @@ public class AdminServiceAPI { ...@@ -362,8 +363,8 @@ public class AdminServiceAPI {
Integer Integer
count = count =
restTemplate.get(env, restTemplate.get(env,
"/instances/by-namespace/count?appId={appId}&clusterName={clusterName}&namespaceName={namespaceName}", "/instances/by-namespace/count?appId={appId}&clusterName={clusterName}&namespaceName={namespaceName}",
Integer.class, appId, clusterName, namespaceName); Integer.class, appId, clusterName, namespaceName);
if (count == null) { if (count == null) {
return 0; return 0;
} }
...@@ -375,39 +376,39 @@ public class AdminServiceAPI { ...@@ -375,39 +376,39 @@ public class AdminServiceAPI {
public static class NamespaceBranchAPI extends API { public static class NamespaceBranchAPI extends API {
public NamespaceDTO createBranch(String appId, Env env, String clusterName, public NamespaceDTO createBranch(String appId, Env env, String clusterName,
String namespaceName, String operator) { String namespaceName, String operator) {
return restTemplate return restTemplate
.post(env, "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches?operator={operator}", .post(env, "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches?operator={operator}",
null, NamespaceDTO.class, appId, clusterName, namespaceName, operator); null, NamespaceDTO.class, appId, clusterName, namespaceName, operator);
} }
public NamespaceDTO findBranch(String appId, Env env, String clusterName, public NamespaceDTO findBranch(String appId, Env env, String clusterName,
String namespaceName) { String namespaceName) {
return restTemplate.get(env, "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches", return restTemplate.get(env, "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches",
NamespaceDTO.class, appId, clusterName, namespaceName); NamespaceDTO.class, appId, clusterName, namespaceName);
} }
public GrayReleaseRuleDTO findBranchGrayRules(String appId, Env env, String clusterName, public GrayReleaseRuleDTO findBranchGrayRules(String appId, Env env, String clusterName,
String namespaceName, String branchName) { String namespaceName, String branchName) {
return restTemplate return restTemplate
.get(env, "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/rules", .get(env, "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/rules",
GrayReleaseRuleDTO.class, appId, clusterName, namespaceName, branchName); GrayReleaseRuleDTO.class, appId, clusterName, namespaceName, branchName);
} }
public void updateBranchGrayRules(String appId, Env env, String clusterName, public void updateBranchGrayRules(String appId, Env env, String clusterName,
String namespaceName, String branchName, GrayReleaseRuleDTO rules) { String namespaceName, String branchName, GrayReleaseRuleDTO rules) {
restTemplate restTemplate
.put(env, "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/rules", .put(env, "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/rules",
rules, appId, clusterName, namespaceName, branchName); rules, appId, clusterName, namespaceName, branchName);
} }
public void deleteBranch(String appId, Env env, String clusterName, public void deleteBranch(String appId, Env env, String clusterName,
String namespaceName, String branchName, String operator) { String namespaceName, String branchName, String operator) {
restTemplate.delete(env, restTemplate.delete(env,
"/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}?operator={operator}", "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}?operator={operator}",
appId, clusterName, namespaceName, branchName, operator); appId, clusterName, namespaceName, branchName, operator);
} }
} }
...@@ -420,24 +421,24 @@ public class AdminServiceAPI { ...@@ -420,24 +421,24 @@ public class AdminServiceAPI {
public PageDTO<ReleaseHistoryDTO> findReleaseHistoriesByNamespace(String appId, Env env, String clusterName, public PageDTO<ReleaseHistoryDTO> findReleaseHistoriesByNamespace(String appId, Env env, String clusterName,
String namespaceName, int page, int size) { String namespaceName, int page, int size) {
return restTemplate.get(env, return restTemplate.get(env,
"/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/histories?page={page}&size={size}", "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/histories?page={page}&size={size}",
type, appId, clusterName, namespaceName, page, size).getBody(); type, appId, clusterName, namespaceName, page, size).getBody();
} }
public PageDTO<ReleaseHistoryDTO> findByReleaseIdAndOperation(Env env, long releaseId, int operation, int page, public PageDTO<ReleaseHistoryDTO> findByReleaseIdAndOperation(Env env, long releaseId, int operation, int page,
int size) { int size) {
return restTemplate.get(env, return restTemplate.get(env,
"/releases/histories/by_release_id_and_operation?releaseId={releaseId}&operation={operation}&page={page}&size={size}", "/releases/histories/by_release_id_and_operation?releaseId={releaseId}&operation={operation}&page={page}&size={size}",
type, releaseId, operation, page, size).getBody(); type, releaseId, operation, page, size).getBody();
} }
public PageDTO<ReleaseHistoryDTO> findByPreviousReleaseIdAndOperation(Env env, long previousReleaseId, public PageDTO<ReleaseHistoryDTO> findByPreviousReleaseIdAndOperation(Env env, long previousReleaseId,
int operation, int page, int size) { int operation, int page, int size) {
return restTemplate.get(env, return restTemplate.get(env,
"/releases/histories/by_previous_release_id_and_operation?previousReleaseId={releaseId}&operation={operation}&page={page}&size={size}", "/releases/histories/by_previous_release_id_and_operation?previousReleaseId={releaseId}&operation={operation}&page={page}&size={size}",
type, previousReleaseId, operation, page, size).getBody(); type, previousReleaseId, operation, page, size).getBody();
} }
} }
......
package com.ctrip.framework.apollo.portal.controller; package com.ctrip.framework.apollo.portal.controller;
import com.google.common.collect.Sets;
import com.ctrip.framework.apollo.common.entity.App; import com.ctrip.framework.apollo.common.entity.App;
import com.ctrip.framework.apollo.common.exception.BadRequestException; import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.http.MultiResponseEntity; import com.ctrip.framework.apollo.common.http.MultiResponseEntity;
...@@ -14,12 +12,16 @@ import com.ctrip.framework.apollo.portal.component.PortalSettings; ...@@ -14,12 +12,16 @@ import com.ctrip.framework.apollo.portal.component.PortalSettings;
import com.ctrip.framework.apollo.portal.entity.model.AppModel; import com.ctrip.framework.apollo.portal.entity.model.AppModel;
import com.ctrip.framework.apollo.portal.entity.vo.EnvClusterInfo; import com.ctrip.framework.apollo.portal.entity.vo.EnvClusterInfo;
import com.ctrip.framework.apollo.portal.listener.AppCreationEvent; import com.ctrip.framework.apollo.portal.listener.AppCreationEvent;
import com.ctrip.framework.apollo.portal.listener.AppDeletionEvent;
import com.ctrip.framework.apollo.portal.listener.AppInfoChangedEvent; import com.ctrip.framework.apollo.portal.listener.AppInfoChangedEvent;
import com.ctrip.framework.apollo.portal.service.AppService; import com.ctrip.framework.apollo.portal.service.AppService;
import com.ctrip.framework.apollo.portal.service.RolePermissionService; import com.ctrip.framework.apollo.portal.service.RolePermissionService;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder; import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.util.RoleUtils; import com.ctrip.framework.apollo.portal.util.RoleUtils;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
...@@ -36,10 +38,6 @@ import org.springframework.web.bind.annotation.RequestParam; ...@@ -36,10 +38,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpClientErrorException;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@RestController @RestController
@RequestMapping("/apps") @RequestMapping("/apps")
...@@ -82,8 +80,9 @@ public class AppController { ...@@ -82,8 +80,9 @@ public class AppController {
Set<String> admins = appModel.getAdmins(); Set<String> admins = appModel.getAdmins();
if (!CollectionUtils.isEmpty(admins)) { if (!CollectionUtils.isEmpty(admins)) {
rolePermissionService.assignRoleToUsers(RoleUtils.buildAppMasterRoleName(createdApp.getAppId()), rolePermissionService
admins, userInfoHolder.getUser().getUserId()); .assignRoleToUsers(RoleUtils.buildAppMasterRoleName(createdApp.getAppId()),
admins, userInfoHolder.getUser().getUserId());
} }
return createdApp; return createdApp;
...@@ -113,8 +112,8 @@ public class AppController { ...@@ -113,8 +112,8 @@ public class AppController {
response.addResponseEntity(RichResponseEntity.ok(appService.createEnvNavNode(env, appId))); response.addResponseEntity(RichResponseEntity.ok(appService.createEnvNavNode(env, appId)));
} catch (Exception e) { } catch (Exception e) {
response.addResponseEntity(RichResponseEntity.error(HttpStatus.INTERNAL_SERVER_ERROR, response.addResponseEntity(RichResponseEntity.error(HttpStatus.INTERNAL_SERVER_ERROR,
"load env:" + env.name() + " cluster error." + e "load env:" + env.name() + " cluster error." + e
.getMessage())); .getMessage()));
} }
} }
return response; return response;
...@@ -124,8 +123,9 @@ public class AppController { ...@@ -124,8 +123,9 @@ public class AppController {
"application/json"}) "application/json"})
public ResponseEntity<Void> create(@PathVariable String env, @RequestBody App app) { public ResponseEntity<Void> create(@PathVariable String env, @RequestBody App app) {
RequestPrecondition.checkArgumentsNotEmpty(app.getName(), app.getAppId(), app.getOwnerEmail(), app.getOwnerName(), RequestPrecondition.checkArgumentsNotEmpty(app.getName(), app.getAppId(), app.getOwnerEmail(),
app.getOrgId(), app.getOrgName()); app.getOwnerName(),
app.getOrgId(), app.getOrgName());
if (!InputValidator.isValidClusterNamespace(app.getAppId())) { if (!InputValidator.isValidClusterNamespace(app.getAppId())) {
throw new BadRequestException(InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE); throw new BadRequestException(InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE);
} }
...@@ -141,6 +141,15 @@ public class AppController { ...@@ -141,6 +141,15 @@ public class AppController {
return appService.load(appId); return appService.load(appId);
} }
@PreAuthorize(value = "@permissionValidator.isSuperAdmin()")
@RequestMapping(value = "/{appId:.+}", method = RequestMethod.DELETE)
public void deleteApp(@PathVariable String appId) {
App app = appService.deleteAppInLocal(appId);
publisher.publishEvent(new AppDeletionEvent(app));
}
@RequestMapping(value = "/{appId}/miss_envs", method = RequestMethod.GET) @RequestMapping(value = "/{appId}/miss_envs", method = RequestMethod.GET)
public MultiResponseEntity<Env> findMissEnvs(@PathVariable String appId) { public MultiResponseEntity<Env> findMissEnvs(@PathVariable String appId) {
...@@ -154,9 +163,9 @@ public class AppController { ...@@ -154,9 +163,9 @@ public class AppController {
response.addResponseEntity(RichResponseEntity.ok(env)); response.addResponseEntity(RichResponseEntity.ok(env));
} else { } else {
response.addResponseEntity(RichResponseEntity.error(HttpStatus.INTERNAL_SERVER_ERROR, response.addResponseEntity(RichResponseEntity.error(HttpStatus.INTERNAL_SERVER_ERROR,
String.format("load appId:%s from env %s error.", appId, String.format("load appId:%s from env %s error.", appId,
env) env)
+ e.getMessage())); + e.getMessage()));
} }
} }
} }
...@@ -175,16 +184,17 @@ public class AppController { ...@@ -175,16 +184,17 @@ public class AppController {
RequestPrecondition.checkArgumentsNotEmpty(appId, appName, ownerName, orgId, orgName); RequestPrecondition.checkArgumentsNotEmpty(appId, appName, ownerName, orgId, orgName);
if (!InputValidator.isValidClusterNamespace(appModel.getAppId())) { if (!InputValidator.isValidClusterNamespace(appModel.getAppId())) {
throw new BadRequestException(String.format("AppId格式错误: %s", InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE)); throw new BadRequestException(
String.format("AppId格式错误: %s", InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE));
} }
return App.builder() return App.builder()
.appId(appId) .appId(appId)
.name(appName) .name(appName)
.ownerName(ownerName) .ownerName(ownerName)
.orgId(orgId) .orgId(orgId)
.orgName(orgName) .orgName(orgName)
.build(); .build();
} }
} }
package com.ctrip.framework.apollo.portal.listener;
import com.ctrip.framework.apollo.common.entity.App;
import com.google.common.base.Preconditions;
import org.springframework.context.ApplicationEvent;
public class AppDeletionEvent extends ApplicationEvent {
public AppDeletionEvent(Object source) {
super(source);
}
public App getApp() {
Preconditions.checkState(source != null);
return (App) this.source;
}
}
...@@ -5,6 +5,7 @@ import com.ctrip.framework.apollo.common.utils.BeanUtils; ...@@ -5,6 +5,7 @@ import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.core.enums.Env; import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.api.AdminServiceAPI; import com.ctrip.framework.apollo.portal.api.AdminServiceAPI;
import com.ctrip.framework.apollo.portal.component.PortalSettings; import com.ctrip.framework.apollo.portal.component.PortalSettings;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.tracer.Tracer; import com.ctrip.framework.apollo.tracer.Tracer;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -24,7 +25,6 @@ public class AppInfoChangedListener { ...@@ -24,7 +25,6 @@ public class AppInfoChangedListener {
@Autowired @Autowired
private PortalSettings portalSettings; private PortalSettings portalSettings;
@EventListener @EventListener
public void onAppInfoChange(AppInfoChangedEvent event) { public void onAppInfoChange(AppInfoChangedEvent event) {
AppDTO appDTO = BeanUtils.transfrom(AppDTO.class, event.getApp()); AppDTO appDTO = BeanUtils.transfrom(AppDTO.class, event.getApp());
...@@ -39,7 +39,22 @@ public class AppInfoChangedListener { ...@@ -39,7 +39,22 @@ public class AppInfoChangedListener {
Tracer.logError(String.format("Update app's info failed. Env = %s, AppId = %s", env, appId), e); Tracer.logError(String.format("Update app's info failed. Env = %s, AppId = %s", env, appId), e);
} }
} }
} }
@EventListener
public void onAppDelete(AppDeletionEvent event) {
AppDTO appDTO = BeanUtils.transfrom(AppDTO.class, event.getApp());
String appId = appDTO.getAppId();
String operator = appDTO.getDataChangeLastModifiedBy();
List<Env> envs = portalSettings.getActiveEnvs();
for (Env env : envs) {
try {
appAPI.deleteApp(env, appId, operator);
} catch (Throwable e) {
logger.error("Delete app failed. Env = {}, AppId = {}", env, appId, e);
Tracer.logError(String.format("Delete app failed. Env = %s, AppId = %s", env, appId), e);
}
}
}
} }
package com.ctrip.framework.apollo.portal.repository; package com.ctrip.framework.apollo.portal.repository;
import com.ctrip.framework.apollo.common.entity.AppNamespace; import com.ctrip.framework.apollo.common.entity.AppNamespace;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.List; import java.util.List;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface AppNamespaceRepository extends PagingAndSortingRepository<AppNamespace, Long> { public interface AppNamespaceRepository extends PagingAndSortingRepository<AppNamespace, Long> {
...@@ -16,4 +16,7 @@ public interface AppNamespaceRepository extends PagingAndSortingRepository<AppNa ...@@ -16,4 +16,7 @@ public interface AppNamespaceRepository extends PagingAndSortingRepository<AppNa
List<AppNamespace> findByIsPublicTrue(); List<AppNamespace> findByIsPublicTrue();
@Modifying
@Query("UPDATE AppNamespace SET IsDeleted=1,DataChange_LastModifiedBy=?2 WHERE AppId=?1")
int batchDeleteByAppId(String appId, String operator);
} }
...@@ -3,6 +3,8 @@ package com.ctrip.framework.apollo.portal.repository; ...@@ -3,6 +3,8 @@ package com.ctrip.framework.apollo.portal.repository;
import com.ctrip.framework.apollo.common.entity.App; import com.ctrip.framework.apollo.common.entity.App;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.List; import java.util.List;
...@@ -17,4 +19,7 @@ public interface AppRepository extends PagingAndSortingRepository<App, Long> { ...@@ -17,4 +19,7 @@ public interface AppRepository extends PagingAndSortingRepository<App, Long> {
List<App> findByAppIdIn(Set<String> appIds); List<App> findByAppIdIn(Set<String> appIds);
@Modifying
@Query("UPDATE App SET IsDeleted=1,DataChange_LastModifiedBy = ?2 WHERE AppId=?1")
int deleteApp(String appId, String operator);
} }
...@@ -3,6 +3,8 @@ package com.ctrip.framework.apollo.portal.repository; ...@@ -3,6 +3,8 @@ package com.ctrip.framework.apollo.portal.repository;
import com.ctrip.framework.apollo.portal.entity.po.Favorite; import com.ctrip.framework.apollo.portal.entity.po.Favorite;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.List; import java.util.List;
...@@ -16,4 +18,8 @@ public interface FavoriteRepository extends PagingAndSortingRepository<Favorite, ...@@ -16,4 +18,8 @@ public interface FavoriteRepository extends PagingAndSortingRepository<Favorite,
Favorite findFirstByUserIdOrderByPositionAscDataChangeCreatedTimeAsc(String userId); Favorite findFirstByUserIdOrderByPositionAscDataChangeCreatedTimeAsc(String userId);
Favorite findByUserIdAndAppId(String userId, String appId); Favorite findByUserIdAndAppId(String userId, String appId);
@Modifying
@Query("UPDATE Favorite SET IsDeleted=1,DataChange_LastModifiedBy = ?2 WHERE AppId=?1")
int batchDeleteByAppId(String appId, String operator);
} }
...@@ -2,10 +2,13 @@ package com.ctrip.framework.apollo.portal.repository; ...@@ -2,10 +2,13 @@ package com.ctrip.framework.apollo.portal.repository;
import com.ctrip.framework.apollo.portal.entity.po.Permission; import com.ctrip.framework.apollo.portal.entity.po.Permission;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import org.springframework.data.repository.query.Param;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
...@@ -21,4 +24,11 @@ public interface PermissionRepository extends PagingAndSortingRepository<Permiss ...@@ -21,4 +24,11 @@ public interface PermissionRepository extends PagingAndSortingRepository<Permiss
*/ */
List<Permission> findByPermissionTypeInAndTargetId(Collection<String> permissionTypes, List<Permission> findByPermissionTypeInAndTargetId(Collection<String> permissionTypes,
String targetId); String targetId);
@Query("SELECT p.id from Permission p where p.targetId = ?1 or p.targetId like CONCAT(?1, '+%'))")
List<Long> findPermissionIdsByAppId(String appId);
@Modifying
@Query("UPDATE Permission SET IsDeleted=1, DataChange_LastModifiedBy = ?2 WHERE Id in ?1")
Integer batchDelete(List<Long> permissionIds, String operator);
} }
...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.portal.repository; ...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.portal.repository;
import com.ctrip.framework.apollo.portal.entity.po.RolePermission; import com.ctrip.framework.apollo.portal.entity.po.RolePermission;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.Collection; import java.util.Collection;
...@@ -17,4 +19,7 @@ public interface RolePermissionRepository extends PagingAndSortingRepository<Rol ...@@ -17,4 +19,7 @@ public interface RolePermissionRepository extends PagingAndSortingRepository<Rol
*/ */
List<RolePermission> findByRoleIdIn(Collection<Long> roleId); List<RolePermission> findByRoleIdIn(Collection<Long> roleId);
@Modifying
@Query("UPDATE RolePermission SET IsDeleted=1, DataChange_LastModifiedBy = ?2 WHERE PermissionId in ?1")
Integer batchDeleteByPermissionIds(List<Long> permissionIds, String operator);
} }
package com.ctrip.framework.apollo.portal.repository; package com.ctrip.framework.apollo.portal.repository;
import com.ctrip.framework.apollo.portal.entity.po.Role; import com.ctrip.framework.apollo.portal.entity.po.Role;
import java.util.List;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
*/ */
public interface RoleRepository extends PagingAndSortingRepository<Role, Long> { public interface RoleRepository extends PagingAndSortingRepository<Role, Long> {
/** /**
* find role by role name * find role by role name
*/ */
Role findTopByRoleName(String roleName); Role findTopByRoleName(String roleName);
@Query("SELECT r.id from Role r where (r.roleName = CONCAT('Master+', ?1) "
+ "OR r.roleName like CONCAT('ModifyNamespace+', ?1, '+%') "
+ "OR r.roleName like CONCAT('ReleaseNamespace+', ?1, '+%'))")
List<Long> findRoleIdsByAppId(String appId);
@Modifying
@Query("UPDATE Role SET IsDeleted=1, DataChange_LastModifiedBy = ?2 WHERE Id in ?1")
Integer batchDelete(List<Long> roleIds, String operator);
} }
...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.portal.repository; ...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.portal.repository;
import com.ctrip.framework.apollo.portal.entity.po.UserRole; import com.ctrip.framework.apollo.portal.entity.po.UserRole;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.Collection; import java.util.Collection;
...@@ -26,4 +28,8 @@ public interface UserRoleRepository extends PagingAndSortingRepository<UserRole, ...@@ -26,4 +28,8 @@ public interface UserRoleRepository extends PagingAndSortingRepository<UserRole,
*/ */
List<UserRole> findByUserIdInAndRoleId(Collection<String> userId, long roleId); List<UserRole> findByUserIdInAndRoleId(Collection<String> userId, long roleId);
@Modifying
@Query("UPDATE UserRole SET IsDeleted=1, DataChange_LastModifiedBy = ?2 WHERE RoleId in ?1")
Integer batchDeleteByRoleIds(List<Long> roleIds, String operator);
} }
...@@ -118,4 +118,7 @@ public class AppNamespaceService { ...@@ -118,4 +118,7 @@ public class AppNamespaceService {
return createdAppNamespace; return createdAppNamespace;
} }
public void batchDeleteByAppId(String appId, String operator) {
appNamespaceRepository.batchDeleteByAppId(appId, operator);
}
} }
...@@ -41,6 +41,10 @@ public class AppService { ...@@ -41,6 +41,10 @@ public class AppService {
@Autowired @Autowired
private RoleInitializationService roleInitializationService; private RoleInitializationService roleInitializationService;
@Autowired @Autowired
private RolePermissionService rolePermissionService;
@Autowired
private FavoriteService favoriteService;
@Autowired
private UserService userService; private UserService userService;
...@@ -139,4 +143,29 @@ public class AppService { ...@@ -139,4 +143,29 @@ public class AppService {
return node; return node;
} }
@Transactional
public App deleteAppInLocal(String appId) {
App managedApp = appRepository.findByAppId(appId);
if (managedApp == null) {
throw new BadRequestException(String.format("App not exists. AppId = %s", appId));
}
String operator = userInfoHolder.getUser().getUserId();
//this operator is passed to com.ctrip.framework.apollo.portal.listener.AppInfoChangedListener.onAppDelete
managedApp.setDataChangeLastModifiedBy(operator);
//删除portal数据库中的app
appRepository.deleteApp(appId, operator);
//删除portal数据库中的appNamespace
appNamespaceService.batchDeleteByAppId(appId, operator);
//删除portal数据库中的收藏表
favoriteService.batchDeleteByAppId(appId, operator);
//删除portal数据库中Permission、Role相关数据
rolePermissionService.deleteRolePermissionsByAppId(appId, operator);
return managedApp;
}
} }
package com.ctrip.framework.apollo.portal.service; package com.ctrip.framework.apollo.portal.service;
import com.ctrip.framework.apollo.common.exception.BadRequestException; import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.portal.entity.po.Favorite;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.entity.po.Favorite;
import com.ctrip.framework.apollo.portal.repository.FavoriteRepository; import com.ctrip.framework.apollo.portal.repository.FavoriteRepository;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder; import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.spi.UserService; import com.ctrip.framework.apollo.portal.spi.UserService;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@Service @Service
public class FavoriteService { public class FavoriteService {
...@@ -110,4 +108,7 @@ public class FavoriteService { ...@@ -110,4 +108,7 @@ public class FavoriteService {
} }
} }
public void batchDeleteByAppId(String appId, String operator) {
favoriteRepository.batchDeleteByAppId(appId, operator);
}
} }
...@@ -56,4 +56,8 @@ public interface RolePermissionService { ...@@ -56,4 +56,8 @@ public interface RolePermissionService {
*/ */
public Set<Permission> createPermissions(Set<Permission> permissions); public Set<Permission> createPermissions(Set<Permission> permissions);
/**
* delete permissions when delete app.
*/
public void deleteRolePermissionsByAppId(String appId, String operator);
} }
package com.ctrip.framework.apollo.portal.spi.defaultimpl; package com.ctrip.framework.apollo.portal.spi.defaultimpl;
import com.ctrip.framework.apollo.common.entity.BaseEntity;
import com.ctrip.framework.apollo.openapi.repository.ConsumerRoleRepository;
import com.ctrip.framework.apollo.portal.component.config.PortalConfig; import com.ctrip.framework.apollo.portal.component.config.PortalConfig;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
import com.ctrip.framework.apollo.portal.entity.po.Permission; import com.ctrip.framework.apollo.portal.entity.po.Permission;
...@@ -16,6 +18,8 @@ import com.google.common.collect.FluentIterable; ...@@ -16,6 +18,8 @@ import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
...@@ -36,7 +40,8 @@ public class DefaultRolePermissionService implements RolePermissionService { ...@@ -36,7 +40,8 @@ public class DefaultRolePermissionService implements RolePermissionService {
private PermissionRepository permissionRepository; private PermissionRepository permissionRepository;
@Autowired @Autowired
private PortalConfig portalConfig; private PortalConfig portalConfig;
@Autowired
private ConsumerRoleRepository consumerRoleRepository;
/** /**
* Create role with permissions, note that role name should be unique * Create role with permissions, note that role name should be unique
...@@ -220,4 +225,30 @@ public class DefaultRolePermissionService implements RolePermissionService { ...@@ -220,4 +225,30 @@ public class DefaultRolePermissionService implements RolePermissionService {
return FluentIterable.from(results).toSet(); return FluentIterable.from(results).toSet();
} }
@Transactional
@Override
public void deleteRolePermissionsByAppId(String appId, String operator) {
List<Long> permissionIds = permissionRepository.findPermissionIdsByAppId(appId);
if (!permissionIds.isEmpty()) {
// 1. delete Permission
permissionRepository.batchDelete(permissionIds, operator);
// 2. delete Role Permission
rolePermissionRepository.batchDeleteByPermissionIds(permissionIds, operator);
}
List<Long> roleIds = roleRepository.findRoleIdsByAppId(appId);
if (!roleIds.isEmpty()) {
// 3. delete Role
roleRepository.batchDelete(roleIds, operator);
// 4. delete User Role
userRoleRepository.batchDeleteByRoleIds(roleIds, operator);
// 5. delete Consumer Role
consumerRoleRepository.batchDeleteByRoleIds(roleIds, operator);
}
}
} }
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