diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/AppDTO.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/AppDTO.java index ec8d7ce3e06..515b0a273e0 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/AppDTO.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/AppDTO.java @@ -37,6 +37,8 @@ public class AppDTO extends BaseDTO{ private String ownerName; + private String ownerDisplayName; + private String ownerEmail; public long getId() { @@ -47,52 +49,59 @@ public void setId(long id) { this.id = id; } + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + public String getAppId() { return appId; } - public String getName() { - return name; + public void setAppId(String appId) { + this.appId = appId; } public String getOrgId() { return orgId; } + public void setOrgId(String orgId) { + this.orgId = orgId; + } + public String getOrgName() { return orgName; } - public String getOwnerEmail() { - return ownerEmail; + public void setOrgName(String orgName) { + this.orgName = orgName; } public String getOwnerName() { return ownerName; } - public void setAppId(String appId) { - this.appId = appId; + public void setOwnerName(String ownerName) { + this.ownerName = ownerName; } - public void setName(String name) { - this.name = name; + public String getOwnerDisplayName() { + return ownerDisplayName; } - public void setOrgId(String orgId) { - this.orgId = orgId; + public void setOwnerDisplayName(String ownerDisplayName) { + this.ownerDisplayName = ownerDisplayName; } - public void setOrgName(String orgName) { - this.orgName = orgName; + public String getOwnerEmail() { + return ownerEmail; } public void setOwnerEmail(String ownerEmail) { this.ownerEmail = ownerEmail; } - - public void setOwnerName(String ownerName) { - this.ownerName = ownerName; - } - } diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/BaseDTO.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/BaseDTO.java index 6852590214f..6535f37b929 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/BaseDTO.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/BaseDTO.java @@ -25,6 +25,10 @@ public class BaseDTO { protected String dataChangeLastModifiedBy; + protected String dataChangeCreatedByDisplayName; + + protected String dataChangeLastModifiedByDisplayName; + protected Date dataChangeCreatedTime; protected Date dataChangeLastModifiedTime; @@ -45,6 +49,22 @@ public void setDataChangeLastModifiedBy(String dataChangeLastModifiedBy) { this.dataChangeLastModifiedBy = dataChangeLastModifiedBy; } + public String getDataChangeCreatedByDisplayName() { + return dataChangeCreatedByDisplayName; + } + + public void setDataChangeCreatedByDisplayName(String dataChangeCreatedByDisplayName) { + this.dataChangeCreatedByDisplayName = dataChangeCreatedByDisplayName; + } + + public String getDataChangeLastModifiedByDisplayName() { + return dataChangeLastModifiedByDisplayName; + } + + public void setDataChangeLastModifiedByDisplayName(String dataChangeLastModifiedByDisplayName) { + this.dataChangeLastModifiedByDisplayName = dataChangeLastModifiedByDisplayName; + } + public Date getDataChangeCreatedTime() { return dataChangeCreatedTime; } diff --git a/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/AbstractBaseIntegrationTest.java b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/AbstractBaseIntegrationTest.java index 7fb1ca28c73..ee3257c5bdd 100644 --- a/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/AbstractBaseIntegrationTest.java +++ b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/AbstractBaseIntegrationTest.java @@ -34,6 +34,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -41,6 +42,7 @@ import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.RestTemplate; +import java.time.Duration; import java.util.Date; import java.util.Map; import java.util.concurrent.ExecutorService; @@ -62,7 +64,8 @@ public abstract class AbstractBaseIntegrationTest { private static final Gson GSON = new Gson(); - protected RestTemplate restTemplate = (new TestRestTemplate()).getRestTemplate(); + protected RestTemplate restTemplate = (new TestRestTemplate(new RestTemplateBuilder() + .setConnectTimeout(Duration.ofSeconds(5)))).getRestTemplate(); @PostConstruct private void postConstruct() { diff --git a/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/NotificationControllerV2IntegrationTest.java b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/NotificationControllerV2IntegrationTest.java index 59f1538dce6..f97386b70e9 100644 --- a/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/NotificationControllerV2IntegrationTest.java +++ b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/integration/NotificationControllerV2IntegrationTest.java @@ -313,7 +313,7 @@ public void testPollNotificationWthPublicNamespaceAndDataCenter() throws Excepti assertNotEquals(ConfigConsts.NOTIFICATION_ID_PLACEHOLDER, messages.get(key).longValue()); } - @Test(timeout = 5000L) + @Test(timeout = 10000L) @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) public void testPollNotificationWthMultipleNamespacesAndMultipleNamespacesChanged() diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AppController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AppController.java index c302046ef3c..2c126589a7b 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AppController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/AppController.java @@ -17,20 +17,24 @@ package com.ctrip.framework.apollo.portal.controller; +import com.ctrip.framework.apollo.common.dto.AppDTO; import com.ctrip.framework.apollo.common.dto.PageDTO; import com.ctrip.framework.apollo.common.entity.App; import com.ctrip.framework.apollo.common.exception.BadRequestException; import com.ctrip.framework.apollo.common.http.MultiResponseEntity; import com.ctrip.framework.apollo.common.http.RichResponseEntity; +import com.ctrip.framework.apollo.common.utils.BeanUtils; import com.ctrip.framework.apollo.core.ConfigConsts; -import com.ctrip.framework.apollo.portal.environment.Env; import com.ctrip.framework.apollo.portal.component.PortalSettings; +import com.ctrip.framework.apollo.portal.enricher.adapter.AppDtoUserInfoEnrichedAdapter; import com.ctrip.framework.apollo.portal.entity.model.AppModel; import com.ctrip.framework.apollo.portal.entity.po.Role; import com.ctrip.framework.apollo.portal.entity.vo.EnvClusterInfo; +import com.ctrip.framework.apollo.portal.environment.Env; 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.service.AdditionalUserInfoEnrichService; import com.ctrip.framework.apollo.portal.service.AppService; import com.ctrip.framework.apollo.portal.service.RoleInitializationService; import com.ctrip.framework.apollo.portal.service.RolePermissionService; @@ -56,6 +60,7 @@ import org.springframework.web.client.HttpClientErrorException; import javax.validation.Valid; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Set; @@ -71,6 +76,7 @@ public class AppController { private final ApplicationEventPublisher publisher; private final RolePermissionService rolePermissionService; private final RoleInitializationService roleInitializationService; + private final AdditionalUserInfoEnrichService additionalUserInfoEnrichService; public AppController( final UserInfoHolder userInfoHolder, @@ -78,13 +84,15 @@ public AppController( final PortalSettings portalSettings, final ApplicationEventPublisher publisher, final RolePermissionService rolePermissionService, - final RoleInitializationService roleInitializationService) { + final RoleInitializationService roleInitializationService, + final AdditionalUserInfoEnrichService additionalUserInfoEnrichService) { this.userInfoHolder = userInfoHolder; this.appService = appService; this.portalSettings = portalSettings; this.publisher = publisher; this.rolePermissionService = rolePermissionService; this.roleInitializationService = roleInitializationService; + this.additionalUserInfoEnrichService = additionalUserInfoEnrichService; } @GetMapping @@ -182,9 +190,12 @@ public ResponseEntity create(@PathVariable String env, @Valid @RequestBody } @GetMapping("/{appId:.+}") - public App load(@PathVariable String appId) { - - return appService.load(appId); + public AppDTO load(@PathVariable String appId) { + App app = appService.load(appId); + AppDTO appDto = BeanUtils.transform(AppDTO.class, app); + additionalUserInfoEnrichService.enrichAdditionalUserInfo(Collections.singletonList(appDto), + AppDtoUserInfoEnrichedAdapter::new); + return appDto; } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/AdditionalUserInfoEnricher.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/AdditionalUserInfoEnricher.java new file mode 100644 index 00000000000..7bf3f882136 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/AdditionalUserInfoEnricher.java @@ -0,0 +1,35 @@ +/* + * Copyright 2021 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.portal.enricher; + +import com.ctrip.framework.apollo.portal.enricher.adapter.UserInfoEnrichedAdapter; +import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; +import java.util.Map; + +/** + * @author vdisk + */ +public interface AdditionalUserInfoEnricher { + + /** + * enrich an additional user info for the dto list + * + * @param adapter enrich adapter + * @param userInfoMap userInfo map + */ + void enrichAdditionalUserInfo(UserInfoEnrichedAdapter adapter, Map userInfoMap); +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/adapter/AppDtoUserInfoEnrichedAdapter.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/adapter/AppDtoUserInfoEnrichedAdapter.java new file mode 100644 index 00000000000..aef2e6ca746 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/adapter/AppDtoUserInfoEnrichedAdapter.java @@ -0,0 +1,61 @@ +/* + * Copyright 2021 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.portal.enricher.adapter; + +import com.ctrip.framework.apollo.common.dto.AppDTO; + +/** + * @author vdisk + */ +public class AppDtoUserInfoEnrichedAdapter implements UserInfoEnrichedAdapter { + + private final AppDTO dto; + + public AppDtoUserInfoEnrichedAdapter(AppDTO dto) { + this.dto = dto; + } + + @Override + public final String getFirstUserId() { + return this.dto.getDataChangeCreatedBy(); + } + + @Override + public final void setFirstUserDisplayName(String userDisplayName) { + this.dto.setDataChangeCreatedByDisplayName(userDisplayName); + } + + @Override + public final String getSecondUserId() { + return this.dto.getDataChangeLastModifiedBy(); + } + + @Override + public final void setSecondUserDisplayName(String userDisplayName) { + this.dto.setDataChangeLastModifiedByDisplayName(userDisplayName); + } + + @Override + public final String getThirdUserId() { + return this.dto.getOwnerName(); + } + + @Override + public final void setThirdUserDisplayName(String userDisplayName) { + this.dto.setOwnerDisplayName(userDisplayName); + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/adapter/BaseDtoUserInfoEnrichedAdapter.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/adapter/BaseDtoUserInfoEnrichedAdapter.java new file mode 100644 index 00000000000..4c2a3d4bb8b --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/adapter/BaseDtoUserInfoEnrichedAdapter.java @@ -0,0 +1,51 @@ +/* + * Copyright 2021 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.portal.enricher.adapter; + +import com.ctrip.framework.apollo.common.dto.BaseDTO; + +/** + * @author vdisk + */ +public class BaseDtoUserInfoEnrichedAdapter implements UserInfoEnrichedAdapter { + + private final BaseDTO dto; + + public BaseDtoUserInfoEnrichedAdapter(BaseDTO dto) { + this.dto = dto; + } + + @Override + public final String getFirstUserId() { + return this.dto.getDataChangeCreatedBy(); + } + + @Override + public final void setFirstUserDisplayName(String userDisplayName) { + this.dto.setDataChangeCreatedByDisplayName(userDisplayName); + } + + @Override + public final String getSecondUserId() { + return this.dto.getDataChangeLastModifiedBy(); + } + + @Override + public final void setSecondUserDisplayName(String userDisplayName) { + this.dto.setDataChangeLastModifiedByDisplayName(userDisplayName); + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/adapter/UserInfoEnrichedAdapter.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/adapter/UserInfoEnrichedAdapter.java new file mode 100644 index 00000000000..8d0b5bf8ab7 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/adapter/UserInfoEnrichedAdapter.java @@ -0,0 +1,71 @@ +/* + * Copyright 2021 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.portal.enricher.adapter; + +/** + * @author vdisk + */ +public interface UserInfoEnrichedAdapter { + + /** + * get user id from the object + * + * @return user id + */ + String getFirstUserId(); + + /** + * set the user display name for the object + * + * @param userDisplayName user display name + */ + void setFirstUserDisplayName(String userDisplayName); + + /** + * get operator id from the object + * + * @return operator id + */ + default String getSecondUserId() { + return null; + } + + /** + * set the user display name for the object + * + * @param userDisplayName user display name + */ + default void setSecondUserDisplayName(String userDisplayName) { + } + + /** + * get operator id from the object + * + * @return operator id + */ + default String getThirdUserId() { + return null; + } + + /** + * set the user display name for the object + * + * @param userDisplayName user display name + */ + default void setThirdUserDisplayName(String userDisplayName) { + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/impl/UserDisplayNameEnricher.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/impl/UserDisplayNameEnricher.java new file mode 100644 index 00000000000..a0db6e05da3 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/enricher/impl/UserDisplayNameEnricher.java @@ -0,0 +1,54 @@ +/* + * Copyright 2021 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.portal.enricher.impl; + +import com.ctrip.framework.apollo.portal.enricher.AdditionalUserInfoEnricher; +import com.ctrip.framework.apollo.portal.enricher.adapter.UserInfoEnrichedAdapter; +import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; +import java.util.Map; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +/** + * @author vdisk + */ +@Component +public class UserDisplayNameEnricher implements AdditionalUserInfoEnricher { + + @Override + public void enrichAdditionalUserInfo(UserInfoEnrichedAdapter adapter, + Map userInfoMap) { + if (StringUtils.hasText(adapter.getFirstUserId())) { + UserInfo userInfo = userInfoMap.get(adapter.getFirstUserId()); + if (userInfo != null && StringUtils.hasText(userInfo.getName())) { + adapter.setFirstUserDisplayName(userInfo.getName()); + } + } + if (StringUtils.hasText(adapter.getSecondUserId())) { + UserInfo userInfo = userInfoMap.get(adapter.getSecondUserId()); + if (userInfo != null && StringUtils.hasText(userInfo.getName())) { + adapter.setSecondUserDisplayName(userInfo.getName()); + } + } + if (StringUtils.hasText(adapter.getThirdUserId())) { + UserInfo userInfo = userInfoMap.get(adapter.getThirdUserId()); + if (userInfo != null && StringUtils.hasText(userInfo.getName())) { + adapter.setThirdUserDisplayName(userInfo.getName()); + } + } + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ReleaseHistoryBO.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ReleaseHistoryBO.java index a1fde4a1a36..44c247dfc39 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ReleaseHistoryBO.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ReleaseHistoryBO.java @@ -36,6 +36,8 @@ public class ReleaseHistoryBO { private String operator; + private String operatorDisplayName; + private long releaseId; private String releaseTitle; @@ -97,44 +99,28 @@ public void setBranchName(String branchName) { this.branchName = branchName; } - 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 int getOperation() { - return operation; + public String getOperator() { + return operator; } - public void setOperation(int operation) { - this.operation = operation; + public void setOperator(String operator) { + this.operator = operator; } - public Map getOperationContext() { - return operationContext; + public String getOperatorDisplayName() { + return operatorDisplayName; } - public void setOperationContext(Map operationContext) { - this.operationContext = operationContext; + public void setOperatorDisplayName(String operatorDisplayName) { + this.operatorDisplayName = operatorDisplayName; } - public String getOperator() { - return operator; + public long getReleaseId() { + return releaseId; } - public void setOperator(String operator) { - this.operator = operator; + public void setReleaseId(long releaseId) { + this.releaseId = releaseId; } public String getReleaseTitle() { @@ -185,4 +171,28 @@ public boolean isReleaseAbandoned() { public void setReleaseAbandoned(boolean releaseAbandoned) { isReleaseAbandoned = releaseAbandoned; } + + public long getPreviousReleaseId() { + return previousReleaseId; + } + + public void setPreviousReleaseId(long previousReleaseId) { + this.previousReleaseId = previousReleaseId; + } + + public int getOperation() { + return operation; + } + + public void setOperation(int operation) { + this.operation = operation; + } + + public Map getOperationContext() { + return operationContext; + } + + public void setOperationContext(Map operationContext) { + this.operationContext = operationContext; + } } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/UserPO.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/UserPO.java index b1ded16474b..2c32c6c926a 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/UserPO.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/UserPO.java @@ -38,6 +38,8 @@ public class UserPO { private long id; @Column(name = "Username", nullable = false) private String username; + @Column(name = "UserDisplayName", nullable = false) + private String userDisplayName; @Column(name = "Password", nullable = false) private String password; @Column(name = "Email", nullable = false) @@ -61,6 +63,14 @@ public void setUsername(String username) { this.username = username; } + public String getUserDisplayName() { + return userDisplayName; + } + + public void setUserDisplayName(String userDisplayName) { + this.userDisplayName = userDisplayName; + } + public String getEmail() { return email; } @@ -87,8 +97,8 @@ public void setEnabled(int enabled) { public UserInfo toUserInfo() { UserInfo userInfo = new UserInfo(); - userInfo.setName(this.getUsername()); userInfo.setUserId(this.getUsername()); + userInfo.setName(this.getUserDisplayName()); userInfo.setEmail(this.getEmail()); return userInfo; } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/repository/UserRepository.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/repository/UserRepository.java index 1c33c387dad..09edca46517 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/repository/UserRepository.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/repository/UserRepository.java @@ -31,6 +31,8 @@ public interface UserRepository extends PagingAndSortingRepository List findByUsernameLikeAndEnabled(String username, int enabled); + List findByUserDisplayNameLikeAndEnabled(String userDisplayName, int enabled); + UserPO findByUsername(String username); List findByUsernameIn(List userNames); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/AdditionalUserInfoEnrichService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/AdditionalUserInfoEnrichService.java new file mode 100644 index 00000000000..75073ecca8f --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/AdditionalUserInfoEnrichService.java @@ -0,0 +1,36 @@ +/* + * Copyright 2021 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.portal.service; + +import com.ctrip.framework.apollo.portal.enricher.adapter.UserInfoEnrichedAdapter; +import java.util.List; +import java.util.function.Function; + +/** + * @author vdisk + */ +public interface AdditionalUserInfoEnrichService { + + /** + * enrich the additional user info for the object list + * + * @param list object with user id + * @param mapper map the object in the list to {@link UserInfoEnrichedAdapter} + */ + void enrichAdditionalUserInfo(List list, + Function mapper); +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/AdditionalUserInfoEnrichServiceImpl.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/AdditionalUserInfoEnrichServiceImpl.java new file mode 100644 index 00000000000..7288e208016 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/AdditionalUserInfoEnrichServiceImpl.java @@ -0,0 +1,109 @@ +/* + * Copyright 2021 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.portal.service; + +import com.ctrip.framework.apollo.portal.enricher.AdditionalUserInfoEnricher; +import com.ctrip.framework.apollo.portal.enricher.adapter.UserInfoEnrichedAdapter; +import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; +import com.ctrip.framework.apollo.portal.spi.UserService; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +/** + * @author vdisk + */ +@Service +public class AdditionalUserInfoEnrichServiceImpl implements AdditionalUserInfoEnrichService { + + private final UserService userService; + + private final List enricherList; + + public AdditionalUserInfoEnrichServiceImpl( + UserService userService, + List enricherList) { + this.userService = userService; + this.enricherList = enricherList; + } + + @Override + public void enrichAdditionalUserInfo(List list, + Function mapper) { + if (CollectionUtils.isEmpty(list)) { + return; + } + if (CollectionUtils.isEmpty(this.enricherList)) { + return; + } + List adapterList = this.adapt(list, mapper); + if (CollectionUtils.isEmpty(adapterList)) { + return; + } + Set userIdSet = this.extractOperatorId(adapterList); + if (CollectionUtils.isEmpty(userIdSet)) { + return; + } + List userInfoList = this.userService.findByUserIds(new ArrayList<>(userIdSet)); + if (CollectionUtils.isEmpty(userInfoList)) { + return; + } + Map userInfoMap = userInfoList.stream() + .collect(Collectors.toMap(UserInfo::getUserId, Function.identity())); + for (UserInfoEnrichedAdapter adapter : adapterList) { + for (AdditionalUserInfoEnricher enricher : this.enricherList) { + enricher.enrichAdditionalUserInfo(adapter, userInfoMap); + } + } + } + + private List adapt(List dtoList, + Function mapper) { + List adapterList = new ArrayList<>(dtoList.size()); + for (T dto : dtoList) { + if (dto == null) { + continue; + } + UserInfoEnrichedAdapter enrichedAdapter = mapper.apply(dto); + adapterList.add(enrichedAdapter); + } + return adapterList; + } + + private Set extractOperatorId(List adapterList) { + Set operatorIdSet = new HashSet<>(); + for (UserInfoEnrichedAdapter adapter : adapterList) { + if (StringUtils.hasText(adapter.getFirstUserId())) { + operatorIdSet.add(adapter.getFirstUserId()); + } + if (StringUtils.hasText(adapter.getSecondUserId())) { + operatorIdSet.add(adapter.getSecondUserId()); + } + if (StringUtils.hasText(adapter.getThirdUserId())) { + operatorIdSet.add(adapter.getThirdUserId()); + } + } + return operatorIdSet; + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/CommitService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/CommitService.java index ea9ff07c793..fadc208a033 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/CommitService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/CommitService.java @@ -17,6 +17,7 @@ package com.ctrip.framework.apollo.portal.service; import com.ctrip.framework.apollo.common.dto.CommitDTO; +import com.ctrip.framework.apollo.portal.enricher.adapter.BaseDtoUserInfoEnrichedAdapter; import com.ctrip.framework.apollo.portal.environment.Env; import com.ctrip.framework.apollo.portal.api.AdminServiceAPI; import org.springframework.stereotype.Service; @@ -28,13 +29,19 @@ public class CommitService { private final AdminServiceAPI.CommitAPI commitAPI; + private final AdditionalUserInfoEnrichService additionalUserInfoEnrichService; - public CommitService(final AdminServiceAPI.CommitAPI commitAPI) { + public CommitService(final AdminServiceAPI.CommitAPI commitAPI, + AdditionalUserInfoEnrichService additionalUserInfoEnrichService) { this.commitAPI = commitAPI; + this.additionalUserInfoEnrichService = additionalUserInfoEnrichService; } public List find(String appId, Env env, String clusterName, String namespaceName, int page, int size) { - return commitAPI.find(appId, env, clusterName, namespaceName, page, size); + List dtoList = commitAPI.find(appId, env, clusterName, namespaceName, page, size); + this.additionalUserInfoEnrichService.enrichAdditionalUserInfo(dtoList, + BaseDtoUserInfoEnrichedAdapter::new); + return dtoList; } } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/NamespaceService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/NamespaceService.java index 7463b276d5e..ff37c3f08c8 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/NamespaceService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/NamespaceService.java @@ -30,6 +30,7 @@ import com.ctrip.framework.apollo.portal.component.config.PortalConfig; import com.ctrip.framework.apollo.portal.constant.RoleType; import com.ctrip.framework.apollo.portal.constant.TracerEventType; +import com.ctrip.framework.apollo.portal.enricher.adapter.BaseDtoUserInfoEnrichedAdapter; import com.ctrip.framework.apollo.portal.entity.bo.ItemBO; import com.ctrip.framework.apollo.portal.entity.bo.NamespaceBO; import com.ctrip.framework.apollo.portal.environment.Env; @@ -39,14 +40,17 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.gson.Gson; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.*; - @Service public class NamespaceService { @@ -63,6 +67,7 @@ public class NamespaceService { private final InstanceService instanceService; private final NamespaceBranchService branchService; private final RolePermissionService rolePermissionService; + private final AdditionalUserInfoEnrichService additionalUserInfoEnrichService; public NamespaceService( final PortalConfig portalConfig, @@ -74,7 +79,8 @@ public NamespaceService( final AppNamespaceService appNamespaceService, final InstanceService instanceService, final @Lazy NamespaceBranchService branchService, - final RolePermissionService rolePermissionService) { + final RolePermissionService rolePermissionService, + final AdditionalUserInfoEnrichService additionalUserInfoEnrichService) { this.portalConfig = portalConfig; this.portalSettings = portalSettings; this.userInfoHolder = userInfoHolder; @@ -85,6 +91,7 @@ public NamespaceService( this.instanceService = instanceService; this.branchService = branchService; this.rolePermissionService = rolePermissionService; + this.additionalUserInfoEnrichService = additionalUserInfoEnrichService; } @@ -244,6 +251,8 @@ private NamespaceBO transformNamespace2BO(Env env, NamespaceDTO namespace) { //not Release config items List items = itemService.findItems(appId, env, clusterName, namespaceName); + additionalUserInfoEnrichService + .enrichAdditionalUserInfo(items, BaseDtoUserInfoEnrichedAdapter::new); int modifiedItemCnt = 0; for (ItemDTO itemDTO : items) { diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ReleaseHistoryService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ReleaseHistoryService.java index 85008221631..373e90ab658 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ReleaseHistoryService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ReleaseHistoryService.java @@ -22,6 +22,8 @@ import com.ctrip.framework.apollo.common.dto.ReleaseHistoryDTO; import com.ctrip.framework.apollo.common.entity.EntityPair; import com.ctrip.framework.apollo.common.utils.BeanUtils; +import com.ctrip.framework.apollo.portal.api.AdminServiceAPI.ReleaseHistoryAPI; +import com.ctrip.framework.apollo.portal.enricher.adapter.BaseDtoUserInfoEnrichedAdapter; import com.ctrip.framework.apollo.portal.environment.Env; import com.ctrip.framework.apollo.portal.api.AdminServiceAPI; import com.ctrip.framework.apollo.portal.entity.bo.ReleaseHistoryBO; @@ -36,6 +38,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.springframework.util.CollectionUtils; @Service public class ReleaseHistoryService { @@ -44,10 +47,14 @@ public class ReleaseHistoryService { private final AdminServiceAPI.ReleaseHistoryAPI releaseHistoryAPI; private final ReleaseService releaseService; + private final AdditionalUserInfoEnrichService additionalUserInfoEnrichService; - public ReleaseHistoryService(final AdminServiceAPI.ReleaseHistoryAPI releaseHistoryAPI, final ReleaseService releaseService) { + public ReleaseHistoryService(final ReleaseHistoryAPI releaseHistoryAPI, + final ReleaseService releaseService, + AdditionalUserInfoEnrichService additionalUserInfoEnrichService) { this.releaseHistoryAPI = releaseHistoryAPI; this.releaseService = releaseService; + this.additionalUserInfoEnrichService = additionalUserInfoEnrichService; } @@ -97,6 +104,10 @@ public List findNamespaceReleaseHistory(String appId, Env env, private List transformReleaseHistoryDTO2BO(List source, List releases) { + if (CollectionUtils.isEmpty(source)) { + return Collections.emptyList(); + } + this.additionalUserInfoEnrichService.enrichAdditionalUserInfo(source, BaseDtoUserInfoEnrichedAdapter::new); Map releasesMap = BeanUtils.mapByKey("id", releases); @@ -119,6 +130,7 @@ private ReleaseHistoryBO transformReleaseHistoryDTO2BO(ReleaseHistoryDTO dto, Re bo.setReleaseId(dto.getReleaseId()); bo.setPreviousReleaseId(dto.getPreviousReleaseId()); bo.setOperator(dto.getDataChangeCreatedBy()); + bo.setOperatorDisplayName(dto.getDataChangeCreatedByDisplayName()); bo.setOperation(dto.getOperation()); Date releaseTime = dto.getDataChangeLastModifiedTime(); bo.setReleaseTime(releaseTime); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java index 27ef8097e3a..9c81dcc2a24 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java @@ -38,6 +38,7 @@ import com.ctrip.framework.apollo.portal.spi.oidc.ExcludeClientCredentialsClientRegistrationRepository; import com.ctrip.framework.apollo.portal.spi.oidc.OidcAuthenticationSuccessEventListener; import com.ctrip.framework.apollo.portal.spi.oidc.OidcLocalUserService; +import com.ctrip.framework.apollo.portal.spi.oidc.OidcLocalUserServiceImpl; import com.ctrip.framework.apollo.portal.spi.oidc.OidcLogoutHandler; import com.ctrip.framework.apollo.portal.spi.oidc.OidcUserInfoHolder; import com.ctrip.framework.apollo.portal.spi.springsecurity.SpringSecurityUserInfoHolder; @@ -242,8 +243,8 @@ public SsoHeartbeatHandler defaultSsoHeartbeatHandler() { @Bean @ConditionalOnMissingBean(UserInfoHolder.class) - public UserInfoHolder springSecurityUserInfoHolder() { - return new SpringSecurityUserInfoHolder(); + public UserInfoHolder springSecurityUserInfoHolder(UserService userService) { + return new SpringSecurityUserInfoHolder(userService); } @Bean @@ -335,8 +336,8 @@ public SsoHeartbeatHandler defaultSsoHeartbeatHandler() { @Bean @ConditionalOnMissingBean(UserInfoHolder.class) - public UserInfoHolder springSecurityUserInfoHolder() { - return new SpringSecurityUserInfoHolder(); + public UserInfoHolder springSecurityUserInfoHolder(UserService userService) { + return new SpringSecurityUserInfoHolder(userService); } @Bean @@ -460,8 +461,8 @@ public SsoHeartbeatHandler defaultSsoHeartbeatHandler() { @Bean @ConditionalOnMissingBean(UserInfoHolder.class) - public UserInfoHolder oidcUserInfoHolder() { - return new OidcUserInfoHolder(); + public UserInfoHolder oidcUserInfoHolder(UserService userService) { + return new OidcUserInfoHolder(userService); } @Bean @@ -481,7 +482,7 @@ public JdbcUserDetailsManager jdbcUserDetailsManager(AuthenticationManagerBuilde @ConditionalOnMissingBean(UserService.class) public OidcLocalUserService oidcLocalUserService(JdbcUserDetailsManager userDetailsManager, UserRepository userRepository) { - return new OidcLocalUserService(userDetailsManager, userRepository); + return new OidcLocalUserServiceImpl(userDetailsManager, userRepository); } @Bean diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultUserInfoHolder.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultUserInfoHolder.java index 271432e1b12..abe181447b5 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultUserInfoHolder.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultUserInfoHolder.java @@ -33,6 +33,7 @@ public DefaultUserInfoHolder() { public UserInfo getUser() { UserInfo userInfo = new UserInfo(); userInfo.setUserId("apollo"); + userInfo.setName("apollo"); return userInfo; } } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcAuthenticationSuccessEventListener.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcAuthenticationSuccessEventListener.java index e0b6d99dcb7..35f1784b67a 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcAuthenticationSuccessEventListener.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcAuthenticationSuccessEventListener.java @@ -59,13 +59,14 @@ public void onApplicationEvent(AuthenticationSuccessEvent event) { } private void oidcUserLogin(OidcUser oidcUser) { - if (this.contains(oidcUser.getSubject())) { - return; - } UserInfo newUserInfo = new UserInfo(); newUserInfo.setUserId(oidcUser.getSubject()); newUserInfo.setName(oidcUser.getPreferredUsername()); newUserInfo.setEmail(oidcUser.getEmail()); + if (this.contains(oidcUser.getSubject())) { + this.oidcLocalUserService.updateUserInfo(newUserInfo); + return; + } this.oidcLocalUserService.createLocalUser(newUserInfo); } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcLocalUserService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcLocalUserService.java index 26beac68b3c..e782d8b1081 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcLocalUserService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcLocalUserService.java @@ -16,92 +16,25 @@ */ package com.ctrip.framework.apollo.portal.spi.oidc; -import com.ctrip.framework.apollo.core.utils.StringUtils; import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; -import com.ctrip.framework.apollo.portal.entity.po.UserPO; -import com.ctrip.framework.apollo.portal.repository.UserRepository; import com.ctrip.framework.apollo.portal.spi.UserService; -import java.util.Base64; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.Collectors; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.provisioning.JdbcUserDetailsManager; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; /** * @author vdisk */ -public class OidcLocalUserService implements UserService { - - private final Collection authorities = Collections - .singletonList(new SimpleGrantedAuthority("ROLE_USER")); - - private final JdbcUserDetailsManager userDetailsManager; - - private final UserRepository userRepository; - - public OidcLocalUserService( - JdbcUserDetailsManager userDetailsManager, - UserRepository userRepository) { - this.userDetailsManager = userDetailsManager; - this.userRepository = userRepository; - } - - @Transactional(rollbackFor = Exception.class) - public void createLocalUser(UserInfo newUserInfo) { - UserDetails user = new User(newUserInfo.getUserId(), "{nonsensical}" + this.nonsensicalPassword(), authorities); - userDetailsManager.createUser(user); - UserPO managedUser = userRepository.findByUsername(newUserInfo.getUserId()); - if (!StringUtils.isBlank(newUserInfo.getEmail())) { - managedUser.setEmail(newUserInfo.getEmail()); - userRepository.save(managedUser); - } - } +public interface OidcLocalUserService extends UserService { /** - * generate a random password with no meaning + * create local user info related to the oidc user + * + * @param newUserInfo the oidc user's info */ - private String nonsensicalPassword() { - byte[] bytes = new byte[32]; - ThreadLocalRandom.current().nextBytes(bytes); - return Base64.getEncoder().encodeToString(bytes); - } + void createLocalUser(UserInfo newUserInfo); - @Override - public List searchUsers(String keyword, int offset, int limit) { - List users; - if (StringUtils.isEmpty(keyword)) { - users = userRepository.findFirst20ByEnabled(1); - } else { - users = userRepository.findByUsernameLikeAndEnabled("%" + keyword + "%", 1); - } - if (CollectionUtils.isEmpty(users)) { - return Collections.emptyList(); - } - return users.stream().map(UserPO::toUserInfo) - .collect(Collectors.toList()); - } - - @Override - public UserInfo findByUserId(String userId) { - UserPO userPO = userRepository.findByUsername(userId); - return userPO == null ? null : userPO.toUserInfo(); - } - - @Override - public List findByUserIds(List userIds) { - List users = userRepository.findByUsernameIn(userIds); - if (CollectionUtils.isEmpty(users)) { - return Collections.emptyList(); - } - return users.stream().map(UserPO::toUserInfo) - .collect(Collectors.toList()); - } + /** + * update user's info + * + * @param newUserInfo the new user's info + */ + void updateUserInfo(UserInfo newUserInfo); } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcLocalUserServiceImpl.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcLocalUserServiceImpl.java new file mode 100644 index 00000000000..66aca8a4370 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcLocalUserServiceImpl.java @@ -0,0 +1,135 @@ +/* + * Copyright 2021 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.portal.spi.oidc; + +import com.ctrip.framework.apollo.core.utils.StringUtils; +import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; +import com.ctrip.framework.apollo.portal.entity.po.UserPO; +import com.ctrip.framework.apollo.portal.repository.UserRepository; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.provisioning.JdbcUserDetailsManager; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +/** + * @author vdisk + */ +public class OidcLocalUserServiceImpl implements OidcLocalUserService { + + private final Collection authorities = Collections + .singletonList(new SimpleGrantedAuthority("ROLE_USER")); + + private final JdbcUserDetailsManager userDetailsManager; + + private final UserRepository userRepository; + + public OidcLocalUserServiceImpl( + JdbcUserDetailsManager userDetailsManager, + UserRepository userRepository) { + this.userDetailsManager = userDetailsManager; + this.userRepository = userRepository; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void createLocalUser(UserInfo newUserInfo) { + UserDetails user = new User(newUserInfo.getUserId(), + "{nonsensical}" + this.nonsensicalPassword(), authorities); + userDetailsManager.createUser(user); + this.updateUserInfoInternal(newUserInfo); + } + + /** + * generate a random password with no meaning + */ + private String nonsensicalPassword() { + byte[] bytes = new byte[32]; + ThreadLocalRandom.current().nextBytes(bytes); + return Base64.getEncoder().encodeToString(bytes); + } + + private void updateUserInfoInternal(UserInfo newUserInfo) { + UserPO managedUser = userRepository.findByUsername(newUserInfo.getUserId()); + if (!StringUtils.isBlank(newUserInfo.getEmail())) { + managedUser.setEmail(newUserInfo.getEmail()); + } + if (!StringUtils.isBlank(newUserInfo.getName())) { + managedUser.setUserDisplayName(newUserInfo.getName()); + } + userRepository.save(managedUser); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void updateUserInfo(UserInfo newUserInfo) { + this.updateUserInfoInternal(newUserInfo); + } + + @Override + public List searchUsers(String keyword, int offset, int limit) { + List users = this.findUsers(keyword); + if (CollectionUtils.isEmpty(users)) { + return Collections.emptyList(); + } + return users.stream().map(UserPO::toUserInfo) + .collect(Collectors.toList()); + } + + private List findUsers(String keyword) { + if (StringUtils.isEmpty(keyword)) { + return userRepository.findFirst20ByEnabled(1); + } + List users = new ArrayList<>(); + List byUsername = userRepository + .findByUsernameLikeAndEnabled("%" + keyword + "%", 1); + List byUserDisplayName = userRepository + .findByUserDisplayNameLikeAndEnabled("%" + keyword + "%", 1); + if (!CollectionUtils.isEmpty(byUsername)) { + users.addAll(byUsername); + } + if (!CollectionUtils.isEmpty(byUserDisplayName)) { + users.addAll(byUserDisplayName); + } + return users; + } + + @Override + public UserInfo findByUserId(String userId) { + UserPO userPO = userRepository.findByUsername(userId); + return userPO == null ? null : userPO.toUserInfo(); + } + + @Override + public List findByUserIds(List userIds) { + List users = userRepository.findByUsernameIn(userIds); + if (CollectionUtils.isEmpty(users)) { + return Collections.emptyList(); + } + return users.stream().map(UserPO::toUserInfo) + .collect(Collectors.toList()); + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcUserInfoHolder.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcUserInfoHolder.java index 9be967f9818..c32304f1079 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcUserInfoHolder.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/oidc/OidcUserInfoHolder.java @@ -18,6 +18,7 @@ import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; import com.ctrip.framework.apollo.portal.spi.UserInfoHolder; +import com.ctrip.framework.apollo.portal.spi.UserService; import java.security.Principal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,6 +27,7 @@ import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.util.StringUtils; /** * @author vdisk @@ -34,8 +36,26 @@ public class OidcUserInfoHolder implements UserInfoHolder { private static final Logger log = LoggerFactory.getLogger(OidcUserInfoHolder.class); + private final UserService userService; + + public OidcUserInfoHolder(UserService userService) { + this.userService = userService; + } + @Override public UserInfo getUser() { + UserInfo userInfo = this.getUserInternal(); + if (StringUtils.hasText(userInfo.getName())) { + return userInfo; + } + UserInfo userInfoFound = this.userService.findByUserId(userInfo.getUserId()); + if (userInfoFound != null) { + return userInfoFound; + } + return userInfo; + } + + private UserInfo getUserInternal() { Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (principal instanceof OidcUser) { UserInfo userInfo = new UserInfo(); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java index 64cdef27f3b..cf5635f012c 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java @@ -18,7 +18,7 @@ import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; import com.ctrip.framework.apollo.portal.spi.UserInfoHolder; - +import com.ctrip.framework.apollo.portal.spi.UserService; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; @@ -26,10 +26,21 @@ public class SpringSecurityUserInfoHolder implements UserInfoHolder { + private final UserService userService; + + public SpringSecurityUserInfoHolder(UserService userService) { + this.userService = userService; + } + @Override public UserInfo getUser() { + String userId = this.getCurrentUsername(); + UserInfo userInfoFound = this.userService.findByUserId(userId); + if (userInfoFound != null) { + return userInfoFound; + } UserInfo userInfo = new UserInfo(); - userInfo.setUserId(getCurrentUsername()); + userInfo.setUserId(userId); return userInfo; } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserService.java index 3b0539ef5c2..5060e2c9657 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserService.java @@ -74,27 +74,37 @@ public void createOrUpdate(UserPO user) { UserPO managedUser = userRepository.findByUsername(username); managedUser.setEmail(user.getEmail()); + managedUser.setUserDisplayName(user.getUserDisplayName()); userRepository.save(managedUser); } @Override public List searchUsers(String keyword, int offset, int limit) { - List users; - if (StringUtils.isEmpty(keyword)) { - users = userRepository.findFirst20ByEnabled(1); - } else { - users = userRepository.findByUsernameLikeAndEnabled("%" + keyword + "%", 1); - } - - List result = Lists.newArrayList(); + List users = this.findUsers(keyword); if (CollectionUtils.isEmpty(users)) { - return result; + return Collections.emptyList(); } + return users.stream().map(UserPO::toUserInfo) + .collect(Collectors.toList()); + } - result.addAll(users.stream().map(UserPO::toUserInfo).collect(Collectors.toList())); - - return result; + private List findUsers(String keyword) { + if (StringUtils.isEmpty(keyword)) { + return userRepository.findFirst20ByEnabled(1); + } + List users = new ArrayList<>(); + List byUsername = userRepository + .findByUsernameLikeAndEnabled("%" + keyword + "%", 1); + List byUserDisplayName = userRepository + .findByUserDisplayNameLikeAndEnabled("%" + keyword + "%", 1); + if (!CollectionUtils.isEmpty(byUsername)) { + users.addAll(byUsername); + } + if (!CollectionUtils.isEmpty(byUserDisplayName)) { + users.addAll(byUserDisplayName); + } + return users; } @Override diff --git a/apollo-portal/src/main/resources/static/config.html b/apollo-portal/src/main/resources/static/config.html index 71f5bcebc66..2c5ca67f791 100644 --- a/apollo-portal/src/main/resources/static/config.html +++ b/apollo-portal/src/main/resources/static/config.html @@ -102,7 +102,7 @@ {{'Common.AppOwner' | translate }}: - + {{'Common.Email' | translate }}: diff --git a/apollo-portal/src/main/resources/static/config/history.html b/apollo-portal/src/main/resources/static/config/history.html index aafb2bb9a9f..6821540d172 100644 --- a/apollo-portal/src/main/resources/static/config/history.html +++ b/apollo-portal/src/main/resources/static/config/history.html @@ -79,7 +79,7 @@

{{'Config.History.PublishHistory' | translate }}

releaseHistory.operation == 4 || releaseHistory.operation == 7 || releaseHistory.operation == 8, 'release-operation-rollback': releaseHistory.operation == 1 || releaseHistory.operation == 6}"> -

+

diff --git a/apollo-portal/src/main/resources/static/i18n/en.json b/apollo-portal/src/main/resources/static/i18n/en.json index 3313905079b..b0c00c41fc5 100644 --- a/apollo-portal/src/main/resources/static/i18n/en.json +++ b/apollo-portal/src/main/resources/static/i18n/en.json @@ -549,7 +549,8 @@ "SystemRole.AllowedAppMasterAssignRoleTips": "Allow the user '{{userId}}' to add Master as an administrator for AppId:'{{appId}}' Successfully", "UserMange.Title": "User Management", "UserMange.TitleTips": "(Only valid for the default Spring Security simple authentication method: - Dapollo_profile = github,auth)", - "UserMange.UserName": "User Name", + "UserMange.UserName": "User Login Name", + "UserMange.UserDisplayName": "User Display Name", "UserMange.UserNameTips": "If the user name entered does not exist, will create a new one. If it already exists, then it will be updated.", "UserMange.Pwd": "Password", "UserMange.Email": "Email", diff --git a/apollo-portal/src/main/resources/static/i18n/zh-CN.json b/apollo-portal/src/main/resources/static/i18n/zh-CN.json index 6d304944fef..944e8fd3187 100644 --- a/apollo-portal/src/main/resources/static/i18n/zh-CN.json +++ b/apollo-portal/src/main/resources/static/i18n/zh-CN.json @@ -549,7 +549,8 @@ "SystemRole.AllowedAppMasterAssignRoleTips": "添加AppId: '{{appId}}' 的用户: '{{userId}}' 分配应用管理员的权限成功", "UserMange.Title": "用户管理", "UserMange.TitleTips": "(仅对默认的Spring Security简单认证方式有效: -Dapollo_profile=github,auth)", - "UserMange.UserName": "用户名", + "UserMange.UserName": "用户登录账户", + "UserMange.UserDisplayName": "用户名称", "UserMange.UserNameTips": "输入的用户名如果不存在,则新建。若已存在,则更新。", "UserMange.Pwd": "密码", "UserMange.Email": "邮箱", diff --git a/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigBaseInfoController.js b/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigBaseInfoController.js index 1f50d6c69a0..a5008d92737 100644 --- a/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigBaseInfoController.js +++ b/apollo-portal/src/main/resources/static/scripts/controller/config/ConfigBaseInfoController.js @@ -75,6 +75,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, $trans $scope.appBaseInfo = result; $scope.appBaseInfo.orgInfo = result.orgName + '(' + result.orgId + ')'; + $scope.appBaseInfo.ownerInfo = result.ownerDisplayName + '(' + result.ownerName + ')'; loadNavTree(); recordVisitApp(); diff --git a/apollo-portal/src/main/resources/static/scripts/directive/directive.js b/apollo-portal/src/main/resources/static/scripts/directive/directive.js index 05f2a994075..507f93819da 100644 --- a/apollo-portal/src/main/resources/static/scripts/directive/directive.js +++ b/apollo-portal/src/main/resources/static/scripts/directive/directive.js @@ -97,6 +97,7 @@ directive_module.directive('apollonav', UserService.load_user().then(function (result) { scope.userName = result.userId; + scope.userDisplayName = result.name; }, function (result) { }); diff --git a/apollo-portal/src/main/resources/static/user-manage.html b/apollo-portal/src/main/resources/static/user-manage.html index d654aefa8fa..2b56bc276cc 100644 --- a/apollo-portal/src/main/resources/static/user-manage.html +++ b/apollo-portal/src/main/resources/static/user-manage.html @@ -55,6 +55,15 @@ {{'UserMange.UserNameTips' | translate }}
+
+ +
+ +
+