package com.malk.benteler.service; import com.malk.benteler.dto.EiamBatchItemResult; import com.malk.benteler.dto.EiamBatchOperation; import com.malk.benteler.dto.EiamBatchResult; import com.malk.benteler.dto.EiamBatchStage; import com.malk.benteler.dto.EiamCreateUserItem; import com.malk.benteler.dto.EiamDeleteUserItem; import com.malk.benteler.dto.EiamUpdateUserItem; import com.malk.server.common.McException; import com.malk.server.eiam.EiamApiResponse; import com.malk.server.eiam.EiamConf; import com.malk.server.eiam.EiamCustomField; import com.malk.server.eiam.EiamCustomFieldUpdate; import com.malk.service.eiam.EiamClient_User; import com.malk.service.eiam.EiamService; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 本特勒 EIAM 批量业务编排。 */ @Service public class EiamLocalService { private final EiamService eiamService; private final EiamClient_User eiamClientUser; private final EiamConf eiamConf; public EiamLocalService(EiamService eiamService, EiamClient_User eiamClientUser, EiamConf eiamConf) { this.eiamService = eiamService; this.eiamClientUser = eiamClientUser; this.eiamConf = eiamConf; } /** * 批量创建用户,单条失败不中断后续条目。 * * @param items 创建条目 * @return 批量结果 */ public EiamBatchResult batchCreate(List items) { validateBatch(items); String token = eiamService.getAccessToken(); List results = new ArrayList<>(); for (int index = 0; index < items.size(); index++) { results.add(createOne(token, items.get(index), index)); } return EiamBatchResult.of(EiamBatchOperation.CREATE, results); } /** * 批量更新用户,支持账户属性和主组织变更。 * * @param items 更新条目 * @return 批量结果 */ public EiamBatchResult batchUpdate(List items) { validateBatch(items); String token = eiamService.getAccessToken(); List results = new ArrayList<>(); for (int index = 0; index < items.size(); index++) { results.add(updateOne(token, items.get(index), index)); } return EiamBatchResult.of(EiamBatchOperation.UPDATE, results); } /** * 批量删除用户,单条失败不中断后续条目。 * * @param items 删除条目 * @return 批量结果 */ public EiamBatchResult batchDelete(List items) { validateBatch(items); String token = eiamService.getAccessToken(); List results = new ArrayList<>(); for (int index = 0; index < items.size(); index++) { results.add(deleteOne(token, items.get(index), index)); } return EiamBatchResult.of(EiamBatchOperation.DELETE, results); } private EiamBatchItemResult createOne(String token, EiamCreateUserItem item, int index) { EiamBatchStage stage = EiamBatchStage.VALIDATE; try { validateCreateItem(item); stage = EiamBatchStage.CREATE_USER; EiamApiResponse response = eiamClientUser.createUser(token, eiamConf.getInstanceId(), eiamConf.getApplicationId(), item.getUsername(), item.getPrimaryOrganizationalUnitId(), createBody(item)); assertEiamSuccess(response); if (StringUtils.isBlank(response.getUserId())) { throw new McException("EIAM_EMPTY_USER_ID", "CreateUser 成功响应缺少 userId"); } return success(index, item.getFormInstanceId(), item.getUsername(), response.getUserId()); } catch (RuntimeException ex) { return failure(index, item == null ? null : item.getFormInstanceId(), item == null ? null : item.getUsername(), null, stage, ex, false); } } private EiamBatchItemResult updateOne(String token, EiamUpdateUserItem item, int index) { EiamBatchStage stage = EiamBatchStage.VALIDATE; boolean updateCompleted = false; try { validateUpdateItem(item); Map patchBody = updateBody(item); if (!patchBody.isEmpty()) { stage = EiamBatchStage.PATCH_USER; assertEiamSuccess(eiamClientUser.patchUser(token, eiamConf.getInstanceId(), eiamConf.getApplicationId(), item.getUserId(), patchBody)); updateCompleted = true; } if (StringUtils.isNotBlank(item.getPrimaryOrganizationalUnitId())) { stage = EiamBatchStage.SET_PRIMARY_ORG; assertEiamSuccess(eiamClientUser.setUserPrimaryOrganizationalUnit(token, eiamConf.getInstanceId(), eiamConf.getApplicationId(), item.getUserId(), item.getPrimaryOrganizationalUnitId())); updateCompleted = true; } if (StringUtils.isNotBlank(item.getAdditionalOrganizationalUnitId())) { stage = EiamBatchStage.ADD_ORG; assertEiamSuccess(eiamClientUser.addUserToOrganizationalUnits(token, eiamConf.getInstanceId(), eiamConf.getApplicationId(), item.getUserId(), Collections.singletonList(item.getAdditionalOrganizationalUnitId()))); } return success(index, item.getFormInstanceId(), userKey(item), item.getUserId()); } catch (RuntimeException ex) { return failure(index, item == null ? null : item.getFormInstanceId(), item == null ? null : userKey(item), item == null ? null : item.getUserId(), stage, ex, updateCompleted); } } private EiamBatchItemResult deleteOne(String token, EiamDeleteUserItem item, int index) { EiamBatchStage stage = EiamBatchStage.VALIDATE; try { validateFormInstanceId(item == null ? null : item.getFormInstanceId()); if (item == null || StringUtils.isBlank(item.getUserId())) { throw new McException("EIAM_ITEM_INVALID", "userId 不能为空"); } stage = EiamBatchStage.DELETE_USER; assertEiamSuccess(eiamClientUser.deleteUser(token, eiamConf.getInstanceId(), eiamConf.getApplicationId(), item.getUserId())); return success(index, item.getFormInstanceId(), deleteUserKey(item), item.getUserId()); } catch (RuntimeException ex) { return failure(index, item == null ? null : item.getFormInstanceId(), item == null ? null : deleteUserKey(item), item == null ? null : item.getUserId(), stage, ex, false); } } private Map createBody(EiamCreateUserItem item) { Map body = new HashMap<>(); putIfNotBlank(body, "displayName", item.getDisplayName()); String phoneNumber = StringUtils.defaultIfBlank(item.getPhoneNumber(), item.getUsername()); putIfNotBlank(body, "phoneNumber", phoneNumber); if (StringUtils.isNotBlank(phoneNumber)) { body.put("phoneRegion", StringUtils.defaultIfBlank(item.getPhoneRegion(), "86")); body.put("phoneNumberVerified", true); } putIfNotBlank(body, "email", item.getEmail()); if (StringUtils.isNotBlank(item.getEmail())) { body.put("emailVerified", false); } putIfNotBlank(body, "description", item.getDescription()); if (item.getCustomFields() != null) { body.put("customFields", item.getCustomFields()); } Map passwordConfig = new HashMap<>(); passwordConfig.put("passwordInitializationPolicyPriority", "custom"); passwordConfig.put("passwordForcedUpdateStatus", "enabled"); // prd 客户不接收初始密码通知,用户首次登录时通过重置密码流程完成密码设置。 passwordConfig.put("passwordInitializationType", "random"); body.put("passwordInitializationConfig", passwordConfig); return body; } private Map updateBody(EiamUpdateUserItem item) { Map body = new HashMap<>(); putIfNotBlank(body, "username", item.getUsername()); putIfNotBlank(body, "displayName", item.getDisplayName()); putIfNotBlank(body, "phoneNumber", item.getPhoneNumber()); if (StringUtils.isNotBlank(item.getPhoneNumber())) { body.put("phoneRegion", StringUtils.defaultIfBlank(item.getPhoneRegion(), "86")); body.put("phoneNumberVerified", true); } putIfNotBlank(body, "email", item.getEmail()); if (StringUtils.isNotBlank(item.getEmail())) { body.put("emailVerified", false); } if (item.getCustomFields() != null && !item.getCustomFields().isEmpty()) { body.put("customFields", item.getCustomFields()); } return body; } private void validateCreateItem(EiamCreateUserItem item) { validateFormInstanceId(item == null ? null : item.getFormInstanceId()); if (item == null || StringUtils.isBlank(item.getUsername())) { throw new McException("EIAM_ITEM_INVALID", "username 不能为空"); } if (StringUtils.isBlank(item.getDisplayName())) { throw new McException("EIAM_ITEM_INVALID", "displayName 不能为空"); } if (StringUtils.isBlank(item.getPrimaryOrganizationalUnitId())) { throw new McException("EIAM_ITEM_INVALID", "primaryOrganizationalUnitId 不能为空"); } // prd 新增账号必须完整携带宜搭主表和人员子表中的 EIAM 自定义字段。 validateRequiredCustomField(item, "department", "iDaaS 部门名称"); validateRequiredCustomField(item, "company_name", "所属公司"); validateRequiredCustomField(item, "company_code", "公司代码"); validateRequiredCustomField(item, "job_title", "职位"); } private void validateRequiredCustomField(EiamCreateUserItem item, String fieldName, String displayName) { if (item.getCustomFields() != null) { for (EiamCustomField field : item.getCustomFields()) { if (field != null && StringUtils.equals(fieldName, field.getFieldName()) && StringUtils.isNotBlank(field.getFieldValue())) { return; } } } throw new McException("EIAM_ITEM_INVALID", displayName + " 不能为空"); } private void validateUpdateItem(EiamUpdateUserItem item) { validateFormInstanceId(item == null ? null : item.getFormInstanceId()); if (item == null || StringUtils.isBlank(item.getUserId())) { throw new McException("EIAM_ITEM_INVALID", "userId 不能为空"); } if (containsUpdateContent(item, BentelerYidaFormMapper.UPDATE_PHONE) && StringUtils.isBlank(item.getPhoneNumber())) { throw new McException("EIAM_ITEM_INVALID", "手机号不能为空"); } if (containsUpdateContent(item, BentelerYidaFormMapper.UPDATE_EMPLOYEE_NUMBER)) { validateCustomFieldUpdate(item, "employee_id_number", "工号"); } if (containsUpdateContent(item, BentelerYidaFormMapper.UPDATE_JOB_TITLE)) { validateCustomFieldUpdate(item, "job_title", "职位"); } if (updateBody(item).isEmpty() && StringUtils.isBlank(item.getPrimaryOrganizationalUnitId()) && StringUtils.isBlank(item.getAdditionalOrganizationalUnitId())) { throw new McException("EIAM_ITEM_INVALID", "更新内容不能为空"); } } private boolean containsUpdateContent(EiamUpdateUserItem item, String updateContent) { return item.getUpdateContents() != null && item.getUpdateContents().contains(updateContent); } private void validateCustomFieldUpdate(EiamUpdateUserItem item, String fieldName, String displayName) { if (item.getCustomFields() != null) { for (EiamCustomFieldUpdate field : item.getCustomFields()) { if (field != null && StringUtils.equals(fieldName, field.getFieldName()) && StringUtils.isNotBlank(field.getFieldValue())) { return; } } } throw new McException("EIAM_ITEM_INVALID", displayName + " 不能为空"); } private void validateBatch(List items) { if (items == null || items.isEmpty()) { throw new McException("EIAM_BATCH_EMPTY", "items 不能为空"); } } private void validateFormInstanceId(String formInstanceId) { if (StringUtils.isBlank(formInstanceId)) { throw new McException("EIAM_ITEM_INVALID", "formInstanceId 不能为空"); } } private void assertEiamSuccess(EiamApiResponse response) { if (response == null) { throw new McException("EIAM_EMPTY_RESPONSE", "EIAM 响应为空"); } String code = StringUtils.defaultIfBlank(response.getCode(), response.getError()); if (StringUtils.isBlank(code)) { return; } String message = StringUtils.defaultIfBlank(response.getMessage(), response.getErrorDescription()); throw new McException(code, StringUtils.defaultIfBlank(message, "EIAM 调用失败")); } private EiamBatchItemResult success(int index, String formInstanceId, String userKey, String userId) { return EiamBatchItemResult.builder().index(index).formInstanceId(formInstanceId) .userKey(userKey).userId(userId).success(true).stage(EiamBatchStage.COMPLETED) .code("SUCCESS").message("执行成功").build(); } private EiamBatchItemResult failure(int index, String formInstanceId, String userKey, String userId, EiamBatchStage stage, RuntimeException ex, boolean partialUpdate) { String code = ex instanceof McException ? ((McException) ex).getCode() : "EIAM_CALL_ERROR"; String message = StringUtils.defaultIfBlank(ex.getMessage(), "EIAM 调用失败"); if (partialUpdate) { message = "账户属性可能已更新;" + message; } return EiamBatchItemResult.builder().index(index).formInstanceId(formInstanceId) .userKey(userKey).userId(userId).success(false).stage(stage) .code(code).message(message).build(); } private void putIfNotBlank(Map target, String key, String value) { if (StringUtils.isNotBlank(value)) { target.put(key, value); } } private String userKey(EiamUpdateUserItem item) { return StringUtils.defaultIfBlank(item.getUsername(), item.getUserId()); } private String deleteUserKey(EiamDeleteUserItem item) { return StringUtils.defaultIfBlank(item.getUsername(), item.getUserId()); } }