Skip to content

Commit c511583

Browse files
authored
Merge pull request apolloconfig#612 from lepdou/openapi-createnamespace
add create namespace open api
2 parents aeb9230 + 8850633 commit c511583

File tree

20 files changed

+387
-157
lines changed

20 files changed

+387
-157
lines changed

apollo-core/src/main/java/com/ctrip/framework/apollo/core/enums/ConfigFileFormat.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ public String getValue() {
1818
return value;
1919
}
2020

21-
public static ConfigFileFormat fromString(String value){
22-
if (StringUtils.isEmpty(value)){
21+
public static ConfigFileFormat fromString(String value) {
22+
if (StringUtils.isEmpty(value)) {
2323
throw new IllegalArgumentException("value can not be empty");
2424
}
25-
switch (value){
25+
switch (value) {
2626
case "properties":
2727
return Properties;
2828
case "xml":
@@ -36,4 +36,13 @@ public static ConfigFileFormat fromString(String value){
3636
}
3737
throw new IllegalArgumentException(value + " can not map enum");
3838
}
39+
40+
public static boolean isValidFormat(String value) {
41+
try {
42+
fromString(value);
43+
return true;
44+
} catch (IllegalArgumentException e) {
45+
return false;
46+
}
47+
}
3948
}

apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/auth/ConsumerPermissionValidator.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@ public class ConsumerPermissionValidator {
1818
@Autowired
1919
private ConsumerAuthUtil consumerAuthUtil;
2020

21+
2122
public boolean hasModifyNamespacePermission(HttpServletRequest request, String appId, String
2223
namespaceName) {
24+
25+
if (hasCreateNamespacePermission(request, appId)) {
26+
return true;
27+
}
2328
return permissionService.consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request),
2429
PermissionType.MODIFY_NAMESPACE,
2530
RoleUtils.buildNamespaceTargetId(appId, namespaceName));
@@ -28,10 +33,19 @@ public boolean hasModifyNamespacePermission(HttpServletRequest request, String a
2833

2934
public boolean hasReleaseNamespacePermission(HttpServletRequest request, String appId, String
3035
namespaceName) {
36+
if (hasCreateNamespacePermission(request, appId)) {
37+
return true;
38+
}
3139
return permissionService.consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request),
3240
PermissionType.RELEASE_NAMESPACE,
3341
RoleUtils.buildNamespaceTargetId(appId, namespaceName));
3442

3543
}
3644

45+
public boolean hasCreateNamespacePermission(HttpServletRequest request, String appId) {
46+
return permissionService.consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request),
47+
PermissionType.CREATE_NAMESPACE,
48+
appId);
49+
}
50+
3751
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.ctrip.framework.apollo.openapi.dto;
2+
3+
4+
import com.ctrip.framework.apollo.common.dto.BaseDTO;
5+
6+
public class OpenAppNamespaceDTO extends BaseDTO {
7+
8+
private String name;
9+
10+
private String appId;
11+
12+
private String format;
13+
14+
private boolean isPublic;
15+
16+
private String comment;
17+
18+
public String getName() {
19+
return name;
20+
}
21+
22+
public void setName(String name) {
23+
this.name = name;
24+
}
25+
26+
public String getAppId() {
27+
return appId;
28+
}
29+
30+
public void setAppId(String appId) {
31+
this.appId = appId;
32+
}
33+
34+
public String getFormat() {
35+
return format;
36+
}
37+
38+
public void setFormat(String format) {
39+
this.format = format;
40+
}
41+
42+
public boolean isPublic() {
43+
return isPublic;
44+
}
45+
46+
public void setPublic(boolean aPublic) {
47+
isPublic = aPublic;
48+
}
49+
50+
public String getComment() {
51+
return comment;
52+
}
53+
54+
public void setComment(String comment) {
55+
this.comment = comment;
56+
}
57+
}

apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/service/ConsumerService.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,9 @@ public List<ConsumerRole> assignNamespaceRoleToConsumer(String token, String app
132132
long namespaceReleaseRoleId = namespaceReleaseRole.getId();
133133

134134
ConsumerRole managedModifyRole = consumerRoleRepository.findByConsumerIdAndRoleId(consumerId, namespaceModifyRoleId);
135-
if (managedModifyRole != null) {
136-
throw new BadRequestException("Namespace's role has assigned to consumer.");
135+
ConsumerRole managedReleaseRole = consumerRoleRepository.findByConsumerIdAndRoleId(consumerId, namespaceReleaseRoleId);
136+
if (managedModifyRole != null && managedReleaseRole != null) {
137+
return Arrays.asList(managedModifyRole, managedReleaseRole);
137138
}
138139

139140
String operator = userInfoHolder.getUser().getUserId();
@@ -147,6 +148,29 @@ public List<ConsumerRole> assignNamespaceRoleToConsumer(String token, String app
147148
return Arrays.asList(createdModifyConsumerRole, createdReleaseConsumerRole);
148149
}
149150

151+
@Transactional
152+
public ConsumerRole assignAppRoleToConsumer(String token, String appId) {
153+
Long consumerId = getConsumerIdByToken(token);
154+
if (consumerId == null) {
155+
throw new BadRequestException("Token is Illegal");
156+
}
157+
158+
Role masterRole = rolePermissionService.findRoleByRoleName(RoleUtils.buildAppMasterRoleName(appId));
159+
if (masterRole == null) {
160+
throw new BadRequestException("App's role does not exist. Please check whether app has created.");
161+
}
162+
163+
long roleId = masterRole.getId();
164+
ConsumerRole managedModifyRole = consumerRoleRepository.findByConsumerIdAndRoleId(consumerId, roleId);
165+
if (managedModifyRole != null) {
166+
return managedModifyRole;
167+
}
168+
169+
String operator = userInfoHolder.getUser().getUserId();
170+
ConsumerRole consumerRole = createConsumerRole(consumerId, roleId, operator);
171+
return consumerRoleRepository.save(consumerRole);
172+
}
173+
150174
@Transactional
151175
public void createConsumerAudits(Iterable<ConsumerAudit> consumerAudits) {
152176
consumerAuditRepository.save(consumerAudits);

apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiBeanUtils.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
import com.google.common.reflect.TypeToken;
55
import com.google.gson.Gson;
66

7+
import com.ctrip.framework.apollo.common.dto.AppNamespaceDTO;
78
import com.ctrip.framework.apollo.common.dto.ItemDTO;
89
import com.ctrip.framework.apollo.common.dto.NamespaceLockDTO;
910
import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
11+
import com.ctrip.framework.apollo.common.entity.AppNamespace;
1012
import com.ctrip.framework.apollo.common.utils.BeanUtils;
13+
import com.ctrip.framework.apollo.openapi.dto.OpenAppNamespaceDTO;
1114
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
1215
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
1316
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceLockDTO;
@@ -40,6 +43,15 @@ public static ItemDTO transformToItemDTO(OpenItemDTO openItemDTO) {
4043
return BeanUtils.transfrom(ItemDTO.class, openItemDTO);
4144
}
4245

46+
public static OpenAppNamespaceDTO transformToOpenAppNamespaceDTO(AppNamespace appNamespace) {
47+
Preconditions.checkArgument(appNamespace != null);
48+
return BeanUtils.transfrom(OpenAppNamespaceDTO.class, appNamespace);
49+
}
50+
51+
public static AppNamespace transformToAppNamespace(OpenAppNamespaceDTO openAppNamespaceDTO) {
52+
Preconditions.checkArgument(openAppNamespaceDTO != null);
53+
return BeanUtils.transfrom(AppNamespace.class, openAppNamespaceDTO);
54+
}
4355

4456
public static OpenReleaseDTO transformFromReleaseDTO(ReleaseDTO release) {
4557
Preconditions.checkArgument(release != null);

apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/NamespaceController.java

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,88 @@
33

44
import com.ctrip.framework.apollo.common.dto.NamespaceDTO;
55
import com.ctrip.framework.apollo.common.dto.NamespaceLockDTO;
6+
import com.ctrip.framework.apollo.common.entity.AppNamespace;
7+
import com.ctrip.framework.apollo.common.exception.BadRequestException;
8+
import com.ctrip.framework.apollo.common.utils.InputValidator;
9+
import com.ctrip.framework.apollo.common.utils.RequestPrecondition;
10+
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
611
import com.ctrip.framework.apollo.core.enums.Env;
12+
import com.ctrip.framework.apollo.openapi.dto.OpenAppNamespaceDTO;
713
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
814
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceLockDTO;
915
import com.ctrip.framework.apollo.openapi.util.OpenApiBeanUtils;
1016
import com.ctrip.framework.apollo.portal.entity.bo.NamespaceBO;
17+
import com.ctrip.framework.apollo.portal.listener.AppNamespaceCreationEvent;
18+
import com.ctrip.framework.apollo.portal.service.AppNamespaceService;
1119
import com.ctrip.framework.apollo.portal.service.NamespaceLockService;
1220
import com.ctrip.framework.apollo.portal.service.NamespaceService;
21+
import com.ctrip.framework.apollo.portal.spi.UserService;
1322

1423
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.context.ApplicationEventPublisher;
25+
import org.springframework.security.access.prepost.PreAuthorize;
1526
import org.springframework.web.bind.annotation.PathVariable;
27+
import org.springframework.web.bind.annotation.RequestBody;
1628
import org.springframework.web.bind.annotation.RequestMapping;
1729
import org.springframework.web.bind.annotation.RequestMethod;
1830
import org.springframework.web.bind.annotation.RestController;
1931

2032
import java.util.List;
33+
import java.util.Objects;
34+
35+
import javax.servlet.http.HttpServletRequest;
2136

2237
@RestController("openapiNamespaceController")
23-
@RequestMapping("/openapi/v1/envs/{env}")
2438
public class NamespaceController {
2539

2640
@Autowired
2741
private NamespaceLockService namespaceLockService;
2842
@Autowired
2943
private NamespaceService namespaceService;
44+
@Autowired
45+
private AppNamespaceService appNamespaceService;
46+
@Autowired
47+
private ApplicationEventPublisher publisher;
48+
@Autowired
49+
private UserService userService;
50+
51+
52+
@PreAuthorize(value = "@consumerPermissionValidator.hasCreateNamespacePermission(#request, #appId)")
53+
@RequestMapping(value = "/openapi/v1/apps/{appId}/appnamespaces", method = RequestMethod.POST)
54+
public OpenAppNamespaceDTO createNamespace(@PathVariable String appId, @RequestBody OpenAppNamespaceDTO appNamespaceDTO,
55+
HttpServletRequest request) {
56+
57+
if (!Objects.equals(appId, appNamespaceDTO.getAppId())) {
58+
throw new BadRequestException(String.format("AppId not equal. AppId in path = %s, AppId in payload = %s", appId,
59+
appNamespaceDTO.getAppId()));
60+
}
61+
RequestPrecondition.checkArgumentsNotEmpty(appNamespaceDTO.getAppId(), appNamespaceDTO.getName(),
62+
appNamespaceDTO.getFormat(), appNamespaceDTO.getDataChangeCreatedBy());
63+
64+
if (!InputValidator.isValidAppNamespace(appNamespaceDTO.getName())) {
65+
throw new BadRequestException(String.format("Namespace格式错误: %s",
66+
InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & "
67+
+ InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE));
68+
}
69+
70+
if (!ConfigFileFormat.isValidFormat(appNamespaceDTO.getFormat())) {
71+
throw new BadRequestException(String.format("Invalid namespace format. format = %s", appNamespaceDTO.getFormat()));
72+
}
73+
74+
String operator = appNamespaceDTO.getDataChangeCreatedBy();
75+
if (userService.findByUserId(operator) == null) {
76+
throw new BadRequestException(String.format("Illegal user. user = %s", operator));
77+
}
78+
79+
AppNamespace appNamespace = OpenApiBeanUtils.transformToAppNamespace(appNamespaceDTO);
80+
AppNamespace createdAppNamespace = appNamespaceService.createAppNamespaceInLocal(appNamespace);
81+
82+
publisher.publishEvent(new AppNamespaceCreationEvent(createdAppNamespace));
83+
84+
return OpenApiBeanUtils.transformToOpenAppNamespaceDTO(createdAppNamespace);
85+
}
3086

31-
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces", method = RequestMethod.GET)
87+
@RequestMapping(value = "/openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces", method = RequestMethod.GET)
3288
public List<OpenNamespaceDTO> findNamespaces(@PathVariable String appId, @PathVariable String env,
3389
@PathVariable String clusterName) {
3490

@@ -37,7 +93,7 @@ public List<OpenNamespaceDTO> findNamespaces(@PathVariable String appId, @PathVa
3793
.fromString(env), clusterName));
3894
}
3995

40-
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName:.+}", method = RequestMethod.GET)
96+
@RequestMapping(value = "/openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName:.+}", method = RequestMethod.GET)
4197
public OpenNamespaceDTO loadNamespace(@PathVariable String appId, @PathVariable String env,
4298
@PathVariable String clusterName, @PathVariable String
4399
namespaceName) {
@@ -49,7 +105,7 @@ public OpenNamespaceDTO loadNamespace(@PathVariable String appId, @PathVariable
49105
return OpenApiBeanUtils.transformFromNamespaceBO(namespaceBO);
50106
}
51107

52-
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/lock", method = RequestMethod.GET)
108+
@RequestMapping(value = "/openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/lock", method = RequestMethod.GET)
53109
public OpenNamespaceLockDTO getNamespaceLock(@PathVariable String appId, @PathVariable String env,
54110
@PathVariable String clusterName, @PathVariable
55111
String namespaceName) {

apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ReleaseController.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ public class ReleaseController {
3636
@PreAuthorize(value = "@consumerPermissionValidator.hasReleaseNamespacePermission(#request, #appId, #namespaceName)")
3737
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases", method = RequestMethod.POST)
3838
public OpenReleaseDTO createRelease(@PathVariable String appId, @PathVariable String env,
39-
@PathVariable String clusterName, @PathVariable String
40-
namespaceName,
39+
@PathVariable String clusterName,
40+
@PathVariable String namespaceName,
4141
@RequestBody NamespaceReleaseModel model,
4242
HttpServletRequest request) {
4343

4444
checkModel(model != null);
4545
RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(model.getReleasedBy(), model
4646
.getReleaseTitle()),
47-
"releaseTitle and releaseBy can not be empty");
47+
"Params(releaseTitle and releasedBy) can not be empty");
4848

4949
if (userService.findByUserId(model.getReleasedBy()) == null) {
5050
throw new BadRequestException("user(releaseBy) not exists");

apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ConsumerController.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020
import org.springframework.web.bind.annotation.RestController;
2121

2222
import java.util.Calendar;
23+
import java.util.Collections;
2324
import java.util.Date;
2425
import java.util.GregorianCalendar;
2526
import java.util.List;
27+
import java.util.Objects;
2628

2729
/**
2830
* @author Jason Song(song_s@ctrip.com)
@@ -65,17 +67,27 @@ public ConsumerToken getConsumerTokenByAppId(@RequestParam String appId) {
6567

6668
@PreAuthorize(value = "@permissionValidator.isSuperAdmin()")
6769
@RequestMapping(value = "/consumers/{token}/assign-role", method = RequestMethod.POST)
68-
public List<ConsumerRole> assignRoleToConsumer(@PathVariable String token, @RequestBody NamespaceDTO namespace) {
70+
public List<ConsumerRole> assignNamespaceRoleToConsumer(@PathVariable String token,
71+
@RequestParam String type,
72+
@RequestBody NamespaceDTO namespace) {
6973

7074
String appId = namespace.getAppId();
7175
String namespaceName = namespace.getNamespaceName();
7276

73-
if (StringUtils.isContainEmpty(appId, namespaceName)) {
74-
throw new BadRequestException("Params(AppId、NamespaceName) can not be empty.");
77+
if (StringUtils.isEmpty(appId)) {
78+
throw new BadRequestException("Params(AppId) can not be empty.");
7579
}
7680

77-
return consumerService.assignNamespaceRoleToConsumer(token, appId, namespaceName);
81+
if (Objects.equals("AppRole", type)) {
82+
return Collections.singletonList(consumerService.assignAppRoleToConsumer(token, appId));
83+
} else {
84+
if (StringUtils.isEmpty(namespaceName)) {
85+
throw new BadRequestException("Params(NamespaceName) can not be empty.");
86+
}
87+
return consumerService.assignNamespaceRoleToConsumer(token, appId, namespaceName);
88+
}
7889
}
7990

8091

92+
8193
}

0 commit comments

Comments
 (0)