diff --git a/maxkey-core/src/main/java/org/dromara/maxkey/entity/SyncJobConfigField.java b/maxkey-core/src/main/java/org/dromara/maxkey/entity/SyncJobConfigField.java new file mode 100644 index 000000000..d6fe93fb5 --- /dev/null +++ b/maxkey-core/src/main/java/org/dromara/maxkey/entity/SyncJobConfigField.java @@ -0,0 +1,208 @@ +package org.dromara.maxkey.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.dromara.mybatis.jpa.entity.JpaEntity; + +import java.io.Serializable; +import java.util.Date; + +/** + * @Description + * @Author Hunter + * @Date 2024-07-16 + */ + +@Entity +@Table(name = "SYNC_JOB_CONFIG_FIELD") +public class SyncJobConfigField extends JpaEntity implements Serializable { + + private static final long serialVersionUID = 6784822536779144306L; + + /** + * + * ID + */ + @Id + @Column + private Long id; + + /** + * 同步任务ID + */ + @Column + private Long jobId; + + /** + * 规则名 + */ + @Column + private String name; + + /** + * 类型 + */ + @Column + private String objectType; + + /** + * 目标字段 + */ + @Column + private String targetField; + + /** + * 目标字段描述 + */ + @Column + private String targetFieldName; + + /** + * 来源字段 + */ + @Column + private String sourceField; + + /** + * 来源字段描述 + */ + @Column + private String sourceFieldName; + + /** + * 描述 + */ + @Column + private String description; + + /** + * 创建人 + */ + @Column + private Long createUser; + + /** + * 创建时间 + */ + @Column + private Date createTime; + + /** + * 修改人 + */ + @Column + private Long updateUser; + + /** + * 修改时间 + */ + @Column + private Date updateTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getJobId() { + return jobId; + } + + public void setJobId(Long jobId) { + this.jobId = jobId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getObjectType() { + return objectType; + } + + public void setObjectType(String objectType) { + this.objectType = objectType; + } + + public String getTargetField() { + return targetField; + } + + public void setTargetField(String targetField) { + this.targetField = targetField; + } + + public String getTargetFieldName() { + return targetFieldName; + } + + public void setTargetFieldName(String targetFieldName) { + this.targetFieldName = targetFieldName; + } + + public String getSourceField() { + return sourceField; + } + + public void setSourceField(String sourceField) { + this.sourceField = sourceField; + } + + public String getSourceFieldName() { + return sourceFieldName; + } + + public void setSourceFieldName(String sourceFieldName) { + this.sourceFieldName = sourceFieldName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Long getCreateUser() { + return createUser; + } + + public void setCreateUser(Long createUser) { + this.createUser = createUser; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Long getUpdateUser() { + return updateUser; + } + + public void setUpdateUser(Long updateUser) { + this.updateUser = updateUser; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } +} + diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/mapper/SyncJobConfigFieldMapper.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/mapper/SyncJobConfigFieldMapper.java new file mode 100644 index 000000000..953054399 --- /dev/null +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/mapper/SyncJobConfigFieldMapper.java @@ -0,0 +1,24 @@ +package org.dromara.maxkey.persistence.mapper; + +import org.apache.ibatis.annotations.Param; +import org.dromara.maxkey.entity.SyncJobConfigField; +import org.dromara.mybatis.jpa.IJpaMapper; + +import java.util.List; + + +public interface SyncJobConfigFieldMapper extends IJpaMapper { + /*@Select("SELECT * FROM sync_job_config_field WHERE job_id = #{jobId} AND object_type = #{objectType}")*/ + public List findByJobIdAndObjectType(@Param("jobId") Long jobId, @Param("objectType") String objectType); + + public List findByJobId(Long jobId); + + + void deleteFieldMapById(Long id); + + void deleteFiledMapByjobId(Long jobId); + + void deleteByJobIdAndObjectType(@Param("jobId") Long jobId, @Param("objectType") String objectType); +} + + diff --git a/maxkey-persistence/src/main/resources/org/dromara/maxkey/persistence/mapper/xml/mysql/SyncJobConfigFieldMapper.xml b/maxkey-persistence/src/main/resources/org/dromara/maxkey/persistence/mapper/xml/mysql/SyncJobConfigFieldMapper.xml new file mode 100644 index 000000000..d4e6d2925 --- /dev/null +++ b/maxkey-persistence/src/main/resources/org/dromara/maxkey/persistence/mapper/xml/mysql/SyncJobConfigFieldMapper.xml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + DELETE FROM sync_job_config_field s WHERE s.id = #{id} + + + + DELETE FROM sync_job_config_field s WHERE s.job_id = #{jobId} + + + DELETE FROM sync_job_config_field WHERE job_id = #{jobId} AND object_type = #{objectType} + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/dromara/maxkey/synchronizer/activedirectory/ActiveDirectoryOrganizationService.java b/maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/dromara/maxkey/synchronizer/activedirectory/ActiveDirectoryOrganizationService.java index aa482b02a..04d8aab3d 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/dromara/maxkey/synchronizer/activedirectory/ActiveDirectoryOrganizationService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/dromara/maxkey/synchronizer/activedirectory/ActiveDirectoryOrganizationService.java @@ -17,8 +17,11 @@ package org.dromara.maxkey.synchronizer.activedirectory; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; +import java.util.Map; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; @@ -35,14 +38,23 @@ import org.dromara.maxkey.ldap.LdapUtils; import org.dromara.maxkey.ldap.constants.OrganizationalUnit; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.getFieldValue; +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.setFieldValue; + @Service public class ActiveDirectoryOrganizationService extends AbstractSynchronizerService implements ISynchronizerService{ static final Logger _logger = LoggerFactory.getLogger(ActiveDirectoryOrganizationService.class); + @Autowired + private SyncJobConfigFieldService syncJobConfigFieldService; + private static final Integer ORG_TYPE = 2; ActiveDirectoryUtils ldapUtils; public void sync() { @@ -214,6 +226,65 @@ public class ActiveDirectoryOrganizationService extends AbstractSynchronizerSer } return null; } + + public Organizations buildOrgByFiledMap(HashMap attributeMap,String name,String nameInNamespace){ + Organizations org = new Organizations(); + Map filedMap = getFiledMap(Long.parseLong(synchronizer.getId())); + String []namePaths = name.replaceAll(",OU=" , "/") + .replaceAll("OU=" , "/") + .replaceAll(",ou=" , "/") + .replaceAll("ou=" , "/") + .split("/"); + String namePah= "/"+rootOrganization.getOrgName(); + for(int i = namePaths.length -1 ; i >= 0 ; i --) { + namePah = namePah + "/" + namePaths[i]; + } + namePah = namePah.substring(0, namePah.length() - 1); + + org.setLdapDn(nameInNamespace); + org.setNamePath(namePah); + org.setId(org.generateId()); + org.setLevel(namePaths.length); + org.setType("department"); + org.setInstId(this.synchronizer.getInstId()); + org.setStatus(ConstsStatus.ACTIVE); + + for (Map.Entry entry : filedMap.entrySet()) { + String orgProperty = entry.getKey(); + String sourceProperty = entry.getValue(); + try { + Object sourceValue = null; + if(attributeMap.keySet().contains(sourceProperty.toLowerCase())){ + sourceValue = LdapUtils.getAttributeStringValue(sourceProperty, attributeMap); + }else{ + sourceValue = getFieldValue(org, sourceProperty); + } + if (sourceValue != null) { + setFieldValue(org, orgProperty, sourceValue); + } + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | NamingException e) { + e.printStackTrace(); + } + } + org.setOrgCode(org.getId()); + + + + return org; + } + + public Map getFiledMap(Long jobId){ + Map filedMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取用户属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == ORG_TYPE.intValue()){ + filedMap.put(element.getTargetField(),element.getSourceField()); + } + } + return filedMap; + } @@ -225,5 +296,11 @@ public class ActiveDirectoryOrganizationService extends AbstractSynchronizerSer this.ldapUtils = ldapUtils; } + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } } diff --git a/maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/dromara/maxkey/synchronizer/activedirectory/ActiveDirectoryUsersService.java b/maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/dromara/maxkey/synchronizer/activedirectory/ActiveDirectoryUsersService.java index 2c96e9214..533bb21b8 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/dromara/maxkey/synchronizer/activedirectory/ActiveDirectoryUsersService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/dromara/maxkey/synchronizer/activedirectory/ActiveDirectoryUsersService.java @@ -17,7 +17,10 @@ package org.dromara.maxkey.synchronizer.activedirectory; +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; +import java.util.List; +import java.util.Map; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; @@ -36,14 +39,22 @@ import org.dromara.maxkey.ldap.LdapUtils; import org.dromara.maxkey.ldap.constants.ActiveDirectoryUser; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.setFieldValue; + @Service public class ActiveDirectoryUsersService extends AbstractSynchronizerService implements ISynchronizerService{ - static final Logger _logger = LoggerFactory.getLogger(ActiveDirectoryUsersService.class); + final static Logger _logger = LoggerFactory.getLogger(ActiveDirectoryUsersService.class); + @Autowired + private SyncJobConfigFieldService syncJobConfigFieldService; + private static final Integer USER_TYPE = 1; ActiveDirectoryUtils ldapUtils; public void sync() { @@ -130,14 +141,15 @@ public class ActiveDirectoryUsersService extends AbstractSynchronizerService namePah = namePah + "/" + namePaths[i]; } - //namePah = namePah.substring(0, namePah.length()); + namePah = namePah.substring(0, namePah.length()); String deptNamePath= namePah.substring(0, namePah.lastIndexOf("/")); _logger.info("deptNamePath " + deptNamePath); + Organizations deptOrg = orgsNamePathMap.get(deptNamePath); if(deptOrg == null ) { deptOrg = rootOrganization; } - + userInfo.setDepartment(deptOrg.getOrgName()); userInfo.setDepartmentId(deptOrg.getId()); try { @@ -185,7 +197,7 @@ public class ActiveDirectoryUsersService extends AbstractSynchronizerService userInfo.setTimeZone("Asia/Shanghai"); userInfo.setStatus(ConstsStatus.ACTIVE); userInfo.setInstId(this.synchronizer.getInstId()); - + HistorySynchronizer historySynchronizer =new HistorySynchronizer(); historySynchronizer.setId(historySynchronizer.generateId()); historySynchronizer.setSyncId(this.synchronizer.getId()); @@ -203,6 +215,102 @@ public class ActiveDirectoryUsersService extends AbstractSynchronizerService return userInfo; } + public UserInfo buildUserInfoByFieldMap(HashMap attributeMap,String name,String nameInNamespace){ + UserInfo userInfo = new UserInfo(); + userInfo.setLdapDn(nameInNamespace); + userInfo.setId(userInfo.generateId()); + String []namePaths = name.replaceAll(",OU=" , "/") + .replaceAll("OU=" , "/") + .replaceAll(",ou=" , "/") + .replaceAll("ou=" , "/") + .split("/"); + + String namePah= "/"+rootOrganization.getOrgName(); + for(int i = namePaths.length -1 ; i >= 0 ; i --) { + namePah = namePah + "/" + namePaths[i]; + } + + namePah = namePah.substring(0, namePah.length()); + String deptNamePath= namePah.substring(0, namePah.lastIndexOf("/")); + _logger.info("deptNamePath " + deptNamePath); + + Organizations deptOrg = orgsNamePathMap.get(deptNamePath); + if(deptOrg == null ) { + deptOrg = rootOrganization; + } + Map fieldMap = getFieldMap(Long.parseLong(synchronizer.getId())); + for (Map.Entry entry : fieldMap.entrySet()) { + String userInfoProperty = entry.getKey(); + String sourceProperty = entry.getValue(); + try { + + if(sourceProperty.equals("orgName")){ + userInfo.setDepartment(deptOrg.getOrgName()); + continue; + } + if(sourceProperty.equals("id")){ + userInfo.setDepartmentId(deptOrg.getId()); + continue; + } + if(sourceProperty.equals("mobile")){ + userInfo.setMobile(LdapUtils.getAttributeStringValue(sourceProperty, attributeMap).equals("")? + userInfo.getId():LdapUtils.getAttributeStringValue(sourceProperty,attributeMap)); + continue; + } + // 获取源属性的值 + Object sourceValue = LdapUtils.getAttributeStringValue(sourceProperty, attributeMap); + // 设置到 UserInfo 对象 + if (sourceValue != null) { + setFieldValue(userInfo, userInfoProperty, sourceValue); + } + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } catch (NamingException e) { + e.printStackTrace(); + } + } + + try { + userInfo.setLdapDn(nameInNamespace); + userInfo.setUserState("RESIDENT"); + userInfo.setUserType("EMPLOYEE"); + userInfo.setTimeZone("Asia/Shanghai"); + userInfo.setStatus(ConstsStatus.ACTIVE); + userInfo.setInstId(this.synchronizer.getInstId()); + + + HistorySynchronizer historySynchronizer =new HistorySynchronizer(); + historySynchronizer.setId(historySynchronizer.generateId()); + historySynchronizer.setSyncId(this.synchronizer.getId()); + historySynchronizer.setSyncName(this.synchronizer.getName()); + historySynchronizer.setObjectId(userInfo.getId()); + historySynchronizer.setObjectName(userInfo.getUsername()); + historySynchronizer.setObjectType(Organizations.class.getSimpleName()); + historySynchronizer.setInstId(synchronizer.getInstId()); + historySynchronizer.setResult("success"); + this.historySynchronizerService.insert(historySynchronizer); + } catch (Exception e) { + e.printStackTrace(); + } + + + + return userInfo; + } + + public Map getFieldMap(Long jobId){ + Map fieldMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取用户属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == USER_TYPE.intValue()){ + fieldMap.put(element.getTargetField(), element.getSourceField()); + } + } + return fieldMap; + } + public ActiveDirectoryUtils getLdapUtils() { return ldapUtils; } @@ -210,5 +318,12 @@ public class ActiveDirectoryUsersService extends AbstractSynchronizerService public void setLdapUtils(ActiveDirectoryUtils ldapUtils) { this.ldapUtils = ldapUtils; } - + + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } } diff --git a/maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/dromara/maxkey/synchronizer/dingtalk/DingtalkOrganizationService.java b/maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/dromara/maxkey/synchronizer/dingtalk/DingtalkOrganizationService.java index 6d4004a2b..8188ace3e 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/dromara/maxkey/synchronizer/dingtalk/DingtalkOrganizationService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/dromara/maxkey/synchronizer/dingtalk/DingtalkOrganizationService.java @@ -17,6 +17,10 @@ package org.dromara.maxkey.synchronizer.dingtalk; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.LinkedBlockingQueue; @@ -25,8 +29,11 @@ import org.dromara.maxkey.entity.SynchroRelated; import org.dromara.maxkey.entity.idm.Organizations; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; @@ -37,9 +44,15 @@ import com.dingtalk.api.response.OapiV2DepartmentListsubResponse; import com.dingtalk.api.response.OapiV2DepartmentListsubResponse.DeptBaseResponse; import com.taobao.api.ApiException; +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.*; + @Service public class DingtalkOrganizationService extends AbstractSynchronizerService implements ISynchronizerService{ - static final Logger _logger = LoggerFactory.getLogger(DingtalkOrganizationService.class); + final static Logger _logger = LoggerFactory.getLogger(DingtalkOrganizationService.class); + + @Autowired + private SyncJobConfigFieldService syncJobConfigFieldService; + private static final Integer ORG_TYPE = 2; static Long ROOT_DEPT_ID = 1L; @@ -55,7 +68,7 @@ public class DingtalkOrganizationService extends AbstractSynchronizerService im OapiV2DepartmentGetResponse rootDeptRsp = requestDepartment(access_token,ROOT_DEPT_ID); _logger.debug("root dept deptId {} , name {} , parentId {}" ,rootDeptRsp.getResult().getDeptId(), - rootDeptRsp.getResult().getName(), + rootDeptRsp.getResult().getName(), rootDeptRsp.getResult().getParentId()); //root SynchroRelated rootSynchroRelated = buildSynchroRelated(rootOrganization, @@ -81,8 +94,11 @@ public class DingtalkOrganizationService extends AbstractSynchronizerService im SynchroRelated synchroRelated = synchroRelatedService.findByOriginId( this.synchronizer,dept.getDeptId() + "",Organizations.CLASS_TYPE ); - - Organizations organization = buildOrganization(dept); + //Parent + SynchroRelated synchroRelatedParent = + synchroRelatedService.findByOriginId( + this.synchronizer,dept.getParentId() + "",Organizations.CLASS_TYPE); + Organizations organization = buildOrgByFieldMap(dept,synchroRelatedParent); if(synchroRelated == null) { organization.setId(organization.generateId()); organizationsService.insert(organization); @@ -147,11 +163,8 @@ public class DingtalkOrganizationService extends AbstractSynchronizerService im synchronizer.getInstId()); } - public Organizations buildOrganization(DeptBaseResponse dept) { - //Parent - SynchroRelated synchroRelatedParent = - synchroRelatedService.findByOriginId( - this.synchronizer,dept.getParentId() + "",Organizations.CLASS_TYPE); + public Organizations buildOrganization(DeptBaseResponse dept,SynchroRelated synchroRelatedParent) { + Organizations org = new Organizations(); org.setId(dept.getDeptId()+""); org.setOrgCode(dept.getDeptId()+""); @@ -167,6 +180,51 @@ public class DingtalkOrganizationService extends AbstractSynchronizerService im return org; } + public Organizations buildOrgByFieldMap(DeptBaseResponse dept,SynchroRelated synchroRelatedParent){ + Organizations org = new Organizations(); + Map fieldMap = getFieldMap(Long.parseLong(synchronizer.getId())); + + for (Map.Entry entry : fieldMap.entrySet()) { + String orgProperty = entry.getKey(); + String sourceProperty = entry.getValue(); + try { + Object sourceValue = null; + + if (hasField(DeptBaseResponse.class, sourceProperty)) { + sourceValue = getFieldValue(dept, sourceProperty); + } + else if (synchroRelatedParent != null && hasField(SynchroRelated.class, sourceProperty)) { + sourceValue = getFieldValue(synchroRelatedParent, sourceProperty); + } + if (sourceValue != null) { + setFieldValue(org, orgProperty, sourceValue); + } + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + org.setType("department"); + org.setInstId(this.synchronizer.getInstId()); + org.setStatus(ConstsStatus.ACTIVE); + org.setDescription("dingtalk"); + return org; + } + + + + public Map getFieldMap(Long jobId){ + Map FieldMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取用户属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == ORG_TYPE.intValue()){ + FieldMap.put(element.getTargetField(), element.getSourceField()); + } + } + return FieldMap; + } + public String getAccess_token() { @@ -176,5 +234,13 @@ public class DingtalkOrganizationService extends AbstractSynchronizerService im public void setAccess_token(String access_token) { this.access_token = access_token; } + + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } } diff --git a/maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/dromara/maxkey/synchronizer/dingtalk/DingtalkUsersService.java b/maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/dromara/maxkey/synchronizer/dingtalk/DingtalkUsersService.java index a4ee1c256..585fb2429 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/dromara/maxkey/synchronizer/dingtalk/DingtalkUsersService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/dromara/maxkey/synchronizer/dingtalk/DingtalkUsersService.java @@ -17,7 +17,10 @@ package org.dromara.maxkey.synchronizer.dingtalk; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.dromara.maxkey.constants.ConstsStatus; @@ -25,10 +28,13 @@ import org.dromara.maxkey.entity.SynchroRelated; import org.dromara.maxkey.entity.idm.UserInfo; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; @@ -36,11 +42,21 @@ import com.dingtalk.api.request.OapiV2UserListRequest; import com.dingtalk.api.response.OapiV2UserListResponse; import com.dingtalk.api.response.OapiV2UserListResponse.ListUserResponse; +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.*; + @Service public class DingtalkUsersService extends AbstractSynchronizerService implements ISynchronizerService{ static final Logger _logger = LoggerFactory.getLogger(DingtalkUsersService.class); String access_token; + + private static final Integer USER_TYPE = 1; + + + + @Autowired + private SyncJobConfigFieldService syncJobConfigFieldService; + public void sync() { _logger.info("Sync Dingtalk Users..."); @@ -65,7 +81,7 @@ public class DingtalkUsersService extends AbstractSynchronizerService implement for(ListUserResponse user :rsp.getResult().getList()) { _logger.debug("name : {} , {} , {}", user.getName(),user.getLoginId(),user.getUserid()); - UserInfo userInfo = buildUserInfo(user,relatedOrg); + UserInfo userInfo = buildUserInfoByFieldMap(user,relatedOrg); _logger.trace("userInfo {}" , userInfo); userInfo.setPassword(userInfo.getUsername() + UserInfo.DEFAULT_PASSWORD_SUFFIX); userInfoService.saveOrUpdate(userInfo); @@ -96,7 +112,7 @@ public class DingtalkUsersService extends AbstractSynchronizerService implement } } - + public UserInfo buildUserInfo(ListUserResponse user,SynchroRelated relatedOrg) { UserInfo userInfo = new UserInfo(); @@ -121,16 +137,88 @@ public class DingtalkUsersService extends AbstractSynchronizerService implement }else { userInfo.setStatus(ConstsStatus.INACTIVE); } - - userInfo.setInstId(this.synchronizer.getInstId()); + + //userInfo.setInstId(this.synchronizer.getInstId()); userInfo.setDescription("dingtalk "+user.getRemark()); return userInfo; } + public UserInfo buildUserInfoByFieldMap(ListUserResponse user, SynchroRelated relatedOrg){ + UserInfo userInfo = new UserInfo(); + Map fieldMap = getFieldMap(Long.parseLong(synchronizer.getId())); + for (Map.Entry entry : fieldMap.entrySet()) { + + String userInfoProperty = entry.getKey(); + String sourceProperty = entry.getValue(); + + try { + Object sourceValue = null; + + if(sourceProperty.equals("email")){ + userInfo.setEmail(StringUtils.isBlank(user.getEmail())? user.getUserid() +"@maxkey.top":user.getEmail()); + continue; + } + if(sourceProperty.equals("active")){ + userInfo.setStatus(user.getActive()?ConstsStatus.ACTIVE:ConstsStatus.INACTIVE); + continue; + } + if(sourceProperty.equals("remark")){ + userInfo.setDescription("dingtalk "+user.getRemark()); + continue; + } + if(sourceProperty.equals("hiredDate")){ + userInfo.setEntryDate(new DateTime(user.getHiredDate()).toString(DateTimeFormat.forPattern("yyyy-MM-dd"))); + continue; + } + if (hasField(OapiV2UserListResponse.ListUserResponse.class, sourceProperty)) { + sourceValue = getFieldValue(user, sourceProperty); + } + + else if (hasField(SynchroRelated.class, sourceProperty)) { + sourceValue = getFieldValue(relatedOrg, sourceProperty); + } + + if (sourceValue != null) { + setFieldValue(userInfo, userInfoProperty, sourceValue); + } + + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + userInfo.setInstId(this.synchronizer.getInstId()); + userInfo.setUserType("EMPLOYEE"); + userInfo.setUserState("RESIDENT"); + return userInfo; + } + + + public Map getFieldMap(Long jobId){ + Map userFieldMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取用户属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == USER_TYPE.intValue()){ + userFieldMap.put(element.getTargetField(), element.getSourceField()); + } + } + return userFieldMap; + } + + public void setAccess_token(String access_token) { this.access_token = access_token; } + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } + } diff --git a/maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/dromara/maxkey/synchronizer/feishu/FeishuOrganizationService.java b/maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/dromara/maxkey/synchronizer/feishu/FeishuOrganizationService.java index a28d8299c..1ce168f7e 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/dromara/maxkey/synchronizer/feishu/FeishuOrganizationService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/dromara/maxkey/synchronizer/feishu/FeishuOrganizationService.java @@ -17,7 +17,10 @@ package org.dromara.maxkey.synchronizer.feishu; +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.LinkedBlockingQueue; @@ -26,20 +29,31 @@ import org.dromara.maxkey.entity.SynchroRelated; import org.dromara.maxkey.entity.idm.Organizations; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; import org.dromara.maxkey.synchronizer.feishu.entity.FeishuDepts; import org.dromara.maxkey.synchronizer.feishu.entity.FeishuDeptsResponse; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; import org.dromara.maxkey.util.AuthorizationHeaderUtils; import org.dromara.maxkey.util.JsonUtils; import org.dromara.maxkey.web.HttpRequestAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.*; + @Service public class FeishuOrganizationService extends AbstractSynchronizerService implements ISynchronizerService{ static final Logger _logger = LoggerFactory.getLogger(FeishuOrganizationService.class); String access_token; + private static final Integer ORG_TYPE = 2; + + + + @Autowired + private SyncJobConfigFieldService syncJobConfigFieldService; static String DEPTS_URL = "https://open.feishu.cn/open-apis/contact/v3/departments/%s/children?page_size=50"; static String ROOT_DEPT_URL = "https://open.feishu.cn/open-apis/contact/v3/departments/%s"; @@ -75,7 +89,11 @@ public class FeishuOrganizationService extends AbstractSynchronizerService imple SynchroRelated synchroRelated = synchroRelatedService.findByOriginId( this.synchronizer,dept.getOpen_department_id(),Organizations.CLASS_TYPE ); - Organizations organization = buildOrganization(dept); + //Parent + SynchroRelated synchroRelatedParent = + synchroRelatedService.findByOriginId( + this.synchronizer,dept.getParent_department_id(),Organizations.CLASS_TYPE); + Organizations organization = buildOrganizationByFieldMap(dept,synchroRelatedParent); if(synchroRelated == null) { organization.setId(organization.generateId()); organizationsService.insert(organization); @@ -138,11 +156,8 @@ public class FeishuOrganizationService extends AbstractSynchronizerService imple synchronizer.getInstId()); } - public Organizations buildOrganization(FeishuDepts dept) { - //Parent - SynchroRelated synchroRelatedParent = - synchroRelatedService.findByOriginId( - this.synchronizer,dept.getParent_department_id(),Organizations.CLASS_TYPE); + public Organizations buildOrganization(FeishuDepts dept,SynchroRelated synchroRelatedParent) { + Organizations org = new Organizations(); org.setOrgCode(dept.getDepartment_id()+""); @@ -157,6 +172,59 @@ public class FeishuOrganizationService extends AbstractSynchronizerService imple return org; } + public Organizations buildOrganizationByFieldMap(FeishuDepts dept,SynchroRelated synchroRelatedParent){ + Map fieldMap = getFiledMap(Long.parseLong(synchronizer.getId())); + Organizations org = new Organizations(); + for (Map.Entry entry : fieldMap.entrySet()) { + String orgProperty = entry.getKey(); + String sourceProperty = entry.getValue(); + try { + Object sourceValue = null; + + if (hasField(dept.getClass(), sourceProperty)) { + sourceValue = getFieldValue(dept, sourceProperty); + } + else if (synchroRelatedParent != null && hasField(SynchroRelated.class, sourceProperty)) { + sourceValue = getFieldValue(synchroRelatedParent, sourceProperty); + } + if (sourceValue != null) { + setFieldValue(org, orgProperty, sourceValue); + } + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + // 额外处理特定逻辑:意味着这些属性不能出现在属性映射表中 + try { + /*if (synchroRelatedParent != null) { + setFieldValue(org, "parentId", synchroRelatedParent.getObjectId()); + setFieldValue(org, "parentName", synchroRelatedParent.getObjectName()); + }*/ + setFieldValue(org, "instId", this.synchronizer.getInstId()); + setFieldValue(org, "status", ConstsStatus.ACTIVE); + setFieldValue(org, "description", "Feishu"); + org.setType("department"); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + return org; + } + + public Map getFiledMap(Long jobId){ + //key是maxkey的属性,value是其他应用的属性 + Map filedMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取组织属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == ORG_TYPE.intValue()){ + filedMap.put(element.getTargetField(), element.getSourceField()); + } + } + return filedMap; + } + public String getAccess_token() { return access_token; } @@ -165,4 +233,12 @@ public class FeishuOrganizationService extends AbstractSynchronizerService imple this.access_token = access_token; } + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } + } diff --git a/maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/dromara/maxkey/synchronizer/feishu/FeishuUsersService.java b/maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/dromara/maxkey/synchronizer/feishu/FeishuUsersService.java index 446d92ebc..60b09ec56 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/dromara/maxkey/synchronizer/feishu/FeishuUsersService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/dromara/maxkey/synchronizer/feishu/FeishuUsersService.java @@ -17,28 +17,38 @@ package org.dromara.maxkey.synchronizer.feishu; +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.List; +import java.util.Map; import org.dromara.maxkey.constants.ConstsStatus; import org.dromara.maxkey.entity.SynchroRelated; import org.dromara.maxkey.entity.idm.UserInfo; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; import org.dromara.maxkey.synchronizer.feishu.entity.FeishuUsers; import org.dromara.maxkey.synchronizer.feishu.entity.FeishuUsersResponse; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; import org.dromara.maxkey.util.AuthorizationHeaderUtils; import org.dromara.maxkey.util.JsonUtils; import org.dromara.maxkey.web.HttpRequestAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; + +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.*; + @Service public class FeishuUsersService extends AbstractSynchronizerService implements ISynchronizerService{ - static final Logger _logger = LoggerFactory.getLogger(FeishuUsersService.class); - + final static Logger _logger = LoggerFactory.getLogger(FeishuUsersService.class); + @Autowired + private SyncJobConfigFieldService syncJobConfigFieldService; String access_token; + private static final Integer USER_TYPE = 1; static String USERS_URL="https://open.feishu.cn/open-apis/contact/v3/users/find_by_department?department_id=%s&page_size=50"; @@ -57,7 +67,7 @@ public class FeishuUsersService extends AbstractSynchronizerService implements I _logger.trace("response : " + responseBody); if(usersResponse.getCode() == 0 && usersResponse.getData().getItems() != null) { for(FeishuUsers feiShuUser : usersResponse.getData().getItems()) { - UserInfo userInfo = buildUserInfo(feiShuUser,relatedOrg); + UserInfo userInfo = buildUserInfoByFieldMapper(feiShuUser,relatedOrg); _logger.debug("userInfo : " + userInfo); userInfo.setPassword(userInfo.getUsername() + UserInfo.DEFAULT_PASSWORD_SUFFIX); userInfoService.saveOrUpdate(userInfo); @@ -89,6 +99,11 @@ public class FeishuUsersService extends AbstractSynchronizerService implements I } } + + + + + public void postSync(UserInfo userInfo) { @@ -124,7 +139,77 @@ public class FeishuUsersService extends AbstractSynchronizerService implements I return userInfo; } + public UserInfo buildUserInfoByFieldMapper(FeishuUsers user,SynchroRelated relatedOrg){ + UserInfo userInfo = new UserInfo(); + Map fieldMap = this.getFiledMap(Long.parseLong(synchronizer.getId())); + for (Map.Entry entry : fieldMap.entrySet()) { + + String userInfoProperty = entry.getKey(); + String sourceProperty = entry.getValue(); + + try { + Object sourceValue = null; + if(sourceProperty.equals("status")){ + if (user.getStatus().isIs_activated()) { + setFieldValue(userInfo, "status", ConstsStatus.ACTIVE); + } else { + setFieldValue(userInfo, "status", ConstsStatus.INACTIVE); + } + continue; + } + if (hasField(user.getClass(), sourceProperty)) { + sourceValue = getFieldValue(user, sourceProperty); + } + else if (hasField(SynchroRelated.class, sourceProperty)) { + sourceValue = getFieldValue(relatedOrg, sourceProperty); + } + + if (sourceValue != null) { + setFieldValue(userInfo, userInfoProperty, sourceValue); + } + + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + // 额外处理特定逻辑 :意味着这些属性映射不能保存在数据库中。 + try { + if(userInfo.getUsername() == null){ + userInfo.setUsername(user.getOpen_id()); + } + setFieldValue(userInfo, "id", userInfo.generateId()); + setFieldValue(userInfo, "instId", this.synchronizer.getInstId()); + userInfo.setUserType("EMPLOYEE"); + userInfo.setUserState("RESIDENT"); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + return userInfo; + } + + public Map getFiledMap(Long jobId){ + Map fieldMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取用户属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == USER_TYPE.intValue()){ + fieldMap.put(element.getTargetField(), element.getSourceField()); + } + } + return fieldMap; + } + public void setAccess_token(String access_token) { this.access_token = access_token; } + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } + + } diff --git a/maxkey-synchronizers/maxkey-synchronizer-jdbc/src/main/java/org/dromara/maxkey/synchronizer/jdbc/JdbcOrganizationService.java b/maxkey-synchronizers/maxkey-synchronizer-jdbc/src/main/java/org/dromara/maxkey/synchronizer/jdbc/JdbcOrganizationService.java index 025b34f11..d99be421a 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-jdbc/src/main/java/org/dromara/maxkey/synchronizer/jdbc/JdbcOrganizationService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-jdbc/src/main/java/org/dromara/maxkey/synchronizer/jdbc/JdbcOrganizationService.java @@ -25,9 +25,13 @@ import org.dromara.maxkey.entity.history.HistorySynchronizer; import org.dromara.maxkey.entity.idm.Organizations; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; +import org.dromara.maxkey.synchronizer.utils.MyResultSet; import org.dromara.maxkey.util.JdbcUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.sql.Connection; @@ -35,11 +39,20 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.setFieldValue; @Service public class JdbcOrganizationService extends AbstractSynchronizerService implements ISynchronizerService { static final Logger _logger = LoggerFactory.getLogger(JdbcOrganizationService.class); static ArrayList mapperList = new ArrayList<>(); + @Autowired + private SyncJobConfigFieldService syncJobConfigFieldService; + + private static final Integer ORG_TYPE = 2; @Override public void sync() { @@ -74,6 +87,87 @@ public class JdbcOrganizationService extends AbstractSynchronizerService impleme } } + public Organizations buildOrgByFieldMap(ResultSet rs) throws SQLException{ + Organizations org = new Organizations(); + DbTableMetaData meta = JdbcUtils.getMetaData(rs); + Map fieldMap = getFieldMap(Long.parseLong(synchronizer.getId())); + for (Map.Entry entry : fieldMap.entrySet()) { + String column = entry.getValue(); + String field = entry.getKey(); + Object value = rs.getObject(column); + + if (value != null) { + try { + setFieldValue(org,field,value); + } catch (Exception e) { + _logger.error("setProperty {}", e); + } + } + } + org.setType("department"); + org.setId(org.generateId()); + org.setInstId(synchronizer.getInstId()); + if (meta.getColumnsMap().containsKey("status")) { + org.setStatus(rs.getInt("status")); + } else { + org.setStatus(ConstsStatus.ACTIVE); + } + _logger.debug("Organization {}", org); + + HistorySynchronizer historySynchronizer = new HistorySynchronizer(); + historySynchronizer.setId(historySynchronizer.generateId()); + historySynchronizer.setSyncId(synchronizer.getId()); + historySynchronizer.setSyncName(synchronizer.getName()); + historySynchronizer.setObjectId(org.getId()); + historySynchronizer.setObjectName(org.getOrgName()); + historySynchronizer.setObjectType(Organizations.class.getSimpleName()); + historySynchronizer.setInstId(synchronizer.getInstId()); + historySynchronizer.setResult("success"); + historySynchronizerService.insert(historySynchronizer); + + return org; + } + + public Organizations buildOrgByFieldMapTemp(MyResultSet rs) throws SQLException{ + Organizations org = new Organizations(); + //DbTableMetaData meta = JdbcUtils.getMetaData(rs); + Map fieldMap = getFieldMap(Long.parseLong(synchronizer.getId())); + for (Map.Entry entry : fieldMap.entrySet()) { + String column = entry.getValue(); + String field = entry.getKey(); + Object value = rs.getObject(column); + + if (value != null) { + try { + setFieldValue(org,field,value); + } catch (Exception e) { + _logger.error("setProperty {}", e); + } + } + } + org.setId(org.generateId()); + org.setInstId(synchronizer.getInstId()); + if (rs.getColumnNames().contains("status")) { + org.setStatus(rs.getInt("status")); + } else { + org.setStatus(ConstsStatus.ACTIVE); + } + _logger.debug("Organization {}", org); + + /*HistorySynchronizer historySynchronizer = new HistorySynchronizer(); + historySynchronizer.setId(historySynchronizer.generateId()); + historySynchronizer.setSyncId(synchronizer.getId()); + historySynchronizer.setSyncName(synchronizer.getName()); + historySynchronizer.setObjectId(org.getId()); + historySynchronizer.setObjectName(org.getOrgName()); + historySynchronizer.setObjectType(Organizations.class.getSimpleName()); + historySynchronizer.setInstId(synchronizer.getInstId()); + historySynchronizer.setResult("success"); + historySynchronizerService.insert(historySynchronizer);*/ + + return org; + } + public Organizations buildOrganization(ResultSet rs) throws SQLException { DbTableMetaData meta = JdbcUtils.getMetaData(rs); @@ -121,6 +215,72 @@ public class JdbcOrganizationService extends AbstractSynchronizerService impleme } + public Organizations buildOrganizationTemp(MyResultSet rs) throws SQLException { + //DbTableMetaData meta = JdbcUtils.getMetaData(rs); + Organizations org = new Organizations(); + + for (ColumnFieldMapper mapper : mapperList) { + if (rs.getColumnNames().contains(mapper.getColumn())) { + Object value = null; + if (mapper.getType().equalsIgnoreCase("String")) { + value = rs.getString(mapper.getColumn()); + } else { + value = rs.getInt(mapper.getColumn()); + } + if (value != null) { + try { + PropertyUtils.setSimpleProperty(org, mapper.getField(), value); + } catch (Exception e) { + _logger.error("setSimpleProperty {}", e); + } + } + } + } + + org.setId(org.generateId()); + org.setInstId(synchronizer.getInstId()); + if (rs.getColumnNames().contains("status")) { + org.setStatus(rs.getInt("status")); + } else { + org.setStatus(ConstsStatus.ACTIVE); + } + _logger.debug("Organization {}", org); + + /*HistorySynchronizer historySynchronizer = new HistorySynchronizer(); + historySynchronizer.setId(historySynchronizer.generateId()); + historySynchronizer.setSyncId(synchronizer.getId()); + historySynchronizer.setSyncName(synchronizer.getName()); + historySynchronizer.setObjectId(org.getId()); + historySynchronizer.setObjectName(org.getOrgName()); + historySynchronizer.setObjectType(Organizations.class.getSimpleName()); + historySynchronizer.setInstId(synchronizer.getInstId()); + historySynchronizer.setResult("success"); + historySynchronizerService.insert(historySynchronizer);*/ + + return org; + + } + + public Map getFieldMap(Long jobId){ + Map filedMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取用户属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == ORG_TYPE.intValue()){ + filedMap.put(element.getTargetField(), element.getSourceField()); + } + } + return filedMap; + } + + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } static { mapperList.add(new ColumnFieldMapper("id", "id", "String")); @@ -129,7 +289,7 @@ public class JdbcOrganizationService extends AbstractSynchronizerService impleme mapperList.add(new ColumnFieldMapper("fullname", "fullName", "String")); mapperList.add(new ColumnFieldMapper("parentid", "parentId", "String")); mapperList.add(new ColumnFieldMapper("parentcode", "parentCode", "String")); - mapperList.add(new ColumnFieldMapper("parentname", "parentName", "String")); + mapperList.add(new ColumnFieldMapper(" ", "parentName", "String")); mapperList.add(new ColumnFieldMapper("type", "type", "String")); mapperList.add(new ColumnFieldMapper("codepath", "codePath", "String")); diff --git a/maxkey-synchronizers/maxkey-synchronizer-jdbc/src/main/java/org/dromara/maxkey/synchronizer/jdbc/JdbcUsersService.java b/maxkey-synchronizers/maxkey-synchronizer-jdbc/src/main/java/org/dromara/maxkey/synchronizer/jdbc/JdbcUsersService.java index 9acdb786a..7cdf7d87c 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-jdbc/src/main/java/org/dromara/maxkey/synchronizer/jdbc/JdbcUsersService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-jdbc/src/main/java/org/dromara/maxkey/synchronizer/jdbc/JdbcUsersService.java @@ -25,21 +25,34 @@ import org.dromara.maxkey.entity.history.HistorySynchronizer; import org.dromara.maxkey.entity.idm.UserInfo; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; +import org.dromara.maxkey.synchronizer.utils.MyResultSet; import org.dromara.maxkey.util.JdbcUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.lang.reflect.InvocationTargetException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.setFieldValue; @Service public class JdbcUsersService extends AbstractSynchronizerService implements ISynchronizerService { - static final Logger _logger = LoggerFactory.getLogger(JdbcUsersService.class); + final static Logger _logger = LoggerFactory.getLogger(JdbcUsersService.class); + @Autowired + public SyncJobConfigFieldService syncJobConfigFieldService; + private static final Integer USER_TYPE = 1; static ArrayList mapperList = new ArrayList<>(); @Override @@ -93,6 +106,7 @@ public class JdbcUsersService extends AbstractSynchronizerService implements ISy } } + public UserInfo buildUserInfo(ResultSet rs) throws SQLException { DbTableMetaData meta = JdbcUtils.getMetaData(rs); UserInfo user = new UserInfo(); @@ -153,6 +167,86 @@ public class JdbcUsersService extends AbstractSynchronizerService implements ISy return user; } + + + + public UserInfo buildUserInfoByFieldMap(ResultSet rs) throws SQLException, InvocationTargetException, NoSuchMethodException, IllegalAccessException { + DbTableMetaData meta = JdbcUtils.getMetaData(rs); + UserInfo user = new UserInfo(); + Map fieldMap = getFieldMap(Long.parseLong(synchronizer.getId())); + for(Map.Entry entry: fieldMap.entrySet()){ + + String column = entry.getValue(); + String field = entry.getKey(); + Object value = null; + if(meta.getColumnsMap().containsKey(column) && !field.equals("status") && !field.equals("password")){ + value = rs.getObject(column); + if(value!=null){ + setFieldValue(user,field,value); + } + } + + } + user.setUserType("EMPLOYEE"); + user.setUserState("RESIDENT"); + //password的获取和user的其他属性相关,如果在遍历过程中进行属性映射,需要在password映射之前,先完成其他属性的映射 + if (meta.getColumnsMap().containsKey("status")) { + user.setStatus(rs.getInt("status")); + } else { + user.setStatus(ConstsStatus.ACTIVE); + } + user.setInstId(synchronizer.getInstId()); + // password + if (meta.getColumnsMap().containsKey("password")) { + user.setPassword(rs.getString("password")); + } else { + String last4Char = "6666"; + if (StringUtils.isNotBlank(user.getIdCardNo())) { + last4Char = user.getIdCardNo().substring(user.getIdCardNo().length() - 4); + } else if (StringUtils.isNotBlank(user.getMobile())) { + last4Char = user.getMobile().substring(user.getMobile().length() - 4); + } else if (StringUtils.isNotBlank(user.getEmployeeNumber())) { + last4Char = user.getEmployeeNumber().substring(user.getEmployeeNumber().length() - 4); + } + user.setPassword(user.getUsername() + "@M" + last4Char); + } + + HistorySynchronizer historySynchronizer = new HistorySynchronizer(); + historySynchronizer.setId(historySynchronizer.generateId()); + historySynchronizer.setSyncId(synchronizer.getId()); + historySynchronizer.setSyncName(synchronizer.getName()); + historySynchronizer.setObjectId(user.getId()); + historySynchronizer.setObjectName(user.getUsername()); + historySynchronizer.setObjectType(UserInfo.class.getSimpleName()); + historySynchronizer.setInstId(synchronizer.getInstId()); + historySynchronizer.setResult("success"); + historySynchronizerService.insert(historySynchronizer); + _logger.debug("User {} ", user); + + return user; + } + + public Map getFieldMap(Long jobId){ + Map fieldMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取用户属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == USER_TYPE.intValue()){ + fieldMap.put(element.getTargetField(), element.getSourceField()); + } + } + return fieldMap; + } + + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } + static { mapperList.add(new ColumnFieldMapper("id", "id", "String")); mapperList.add(new ColumnFieldMapper("username", "username", "String")); @@ -191,7 +285,7 @@ public class JdbcUsersService extends AbstractSynchronizerService implements ISy mapperList.add(new ColumnFieldMapper("homestreetaddress", "homeStreetAddress", "String")); mapperList.add(new ColumnFieldMapper("homeaddressformatted", "homeAddressFormatted", "String")); mapperList.add(new ColumnFieldMapper("homeemail", "homeEmail", "String")); - mapperList.add(new ColumnFieldMapper("homephonenumber", "homePhonenumber", "String")); + mapperList.add(new ColumnFieldMapper("homephoneNumber", "homePhonenumber", "String")); mapperList.add(new ColumnFieldMapper("homepostalcode", "homePostalCode", "String")); mapperList.add(new ColumnFieldMapper("homefax", "homeFax", "String")); //company @@ -207,8 +301,8 @@ public class JdbcUsersService extends AbstractSynchronizerService implements ISy mapperList.add(new ColumnFieldMapper("manager", "manager", "String")); mapperList.add(new ColumnFieldMapper("assistantid", "assistantId", "String")); mapperList.add(new ColumnFieldMapper("assistant", "assistant", "String")); - mapperList.add(new ColumnFieldMapper("entrydate", "entrydate", "String")); - mapperList.add(new ColumnFieldMapper("quitdate", "quitdate", "String")); + mapperList.add(new ColumnFieldMapper("entryDate", "entrydate", "String")); + mapperList.add(new ColumnFieldMapper("quitDate", "quitdate", "String")); mapperList.add(new ColumnFieldMapper("ldapdn", "ldapDn", "String")); mapperList.add(new ColumnFieldMapper("description", "description", "String")); diff --git a/maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/dromara/maxkey/synchronizer/ldap/LdapOrganizationService.java b/maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/dromara/maxkey/synchronizer/ldap/LdapOrganizationService.java index b5267df22..3ffb99629 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/dromara/maxkey/synchronizer/ldap/LdapOrganizationService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/dromara/maxkey/synchronizer/ldap/LdapOrganizationService.java @@ -17,8 +17,11 @@ package org.dromara.maxkey.synchronizer.ldap; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; +import java.util.Map; import javax.naming.NamingEnumeration; import javax.naming.NamingException; @@ -35,14 +38,23 @@ import org.dromara.maxkey.ldap.LdapUtils; import org.dromara.maxkey.ldap.constants.OrganizationalUnit; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.getFieldValue; +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.setFieldValue; + @Service public class LdapOrganizationService extends AbstractSynchronizerService implements ISynchronizerService{ - static final Logger _logger = LoggerFactory.getLogger(LdapOrganizationService.class); + final static Logger _logger = LoggerFactory.getLogger(LdapOrganizationService.class); + @Autowired + private SyncJobConfigFieldService syncJobConfigFieldService; + private static final Integer ORG_TYPE = 2; LdapUtils ldapUtils; public void sync() { @@ -212,6 +224,70 @@ public class LdapOrganizationService extends AbstractSynchronizerService implem } return null; } + + + public Organizations buildOrgByFieldMap(HashMap attributeMap,String name,String nameInNamespace){ + Organizations org = new Organizations(); + String []namePaths = name.replaceAll(",OU=" , "/") + .replaceAll("OU=" , "/") + .replaceAll(",ou=" , "/") + .replaceAll("ou=" , "/") + .split("/"); + + String namePah= "/"+rootOrganization.getOrgName(); + for(int i = namePaths.length -1 ; i >= 0 ; i --) { + namePah = namePah + "/" + namePaths[i]; + } + + namePah = namePah.substring(0, namePah.length() - 1); + org.setLdapDn(nameInNamespace); + org.setId(org.generateId()); + org.setNamePath(namePah); + org.setLevel(namePaths.length); + org.setType("department"); + + Map fieldMap = getFieldMap(Long.parseLong(synchronizer.getId())); + for(Map.Entry entry:fieldMap.entrySet()){ + String orgProperty = entry.getKey(); + String sourceProperty = entry.getValue(); + try { + String fieldValue = null; + if(!attributeMap.keySet().contains(sourceProperty.toLowerCase())){ + fieldValue = (String) getFieldValue(org, sourceProperty); + }else { + fieldValue = LdapUtils.getAttributeStringValue(sourceProperty,attributeMap); + } + if(fieldValue!=null){ + setFieldValue(org,orgProperty,fieldValue); + } + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (NamingException e) { + throw new RuntimeException(e); + } + org.setInstId(this.synchronizer.getInstId()); + org.setStatus(ConstsStatus.ACTIVE); + + } + return org; + } + + public Map getFieldMap(Long jobId){ + Map userFiledMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取用户属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == ORG_TYPE.intValue()){ + userFiledMap.put(element.getTargetField(), element.getSourceField()); + } + } + return userFiledMap; + } public LdapUtils getLdapUtils() { @@ -221,6 +297,12 @@ public class LdapOrganizationService extends AbstractSynchronizerService implem public void setLdapUtils(LdapUtils ldapUtils) { this.ldapUtils = ldapUtils; } - - + + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } } diff --git a/maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/dromara/maxkey/synchronizer/ldap/LdapUsersService.java b/maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/dromara/maxkey/synchronizer/ldap/LdapUsersService.java index 6b07b59e0..c7c0af565 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/dromara/maxkey/synchronizer/ldap/LdapUsersService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/dromara/maxkey/synchronizer/ldap/LdapUsersService.java @@ -17,7 +17,10 @@ package org.dromara.maxkey.synchronizer.ldap; +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; +import java.util.List; +import java.util.Map; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; @@ -34,14 +37,23 @@ import org.dromara.maxkey.ldap.LdapUtils; import org.dromara.maxkey.ldap.constants.InetOrgPerson; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.getFieldValue; +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.setFieldValue; + @Service public class LdapUsersService extends AbstractSynchronizerService implements ISynchronizerService{ - static final Logger _logger = LoggerFactory.getLogger(LdapUsersService.class); + final static Logger _logger = LoggerFactory.getLogger(LdapUsersService.class); + @Autowired + public SyncJobConfigFieldService syncJobConfigFieldService; + private static final Integer USER_TYPE = 1; LdapUtils ldapUtils; public void sync() { @@ -121,10 +133,11 @@ public class LdapUsersService extends AbstractSynchronizerService implements IS namePah = namePah + "/" + namePaths[i]; } - //namePah = namePah.substring(0, namePah.length()); + namePah = namePah.substring(0, namePah.length()); String deptNamePath= namePah.substring(0, namePah.lastIndexOf("/")); _logger.info("deptNamePath " + deptNamePath); - Organizations deptOrg = orgsNamePathMap.get(deptNamePath); + + Organizations deptOrg = orgsNamePathMap.get(deptNamePath); userInfo.setDepartment(deptOrg.getOrgName()); userInfo.setDepartmentId(deptOrg.getId()); @@ -189,8 +202,8 @@ public class LdapUsersService extends AbstractSynchronizerService implements IS userInfo.setTimeZone("Asia/Shanghai"); userInfo.setStatus(1); userInfo.setInstId(this.synchronizer.getInstId()); - - HistorySynchronizer historySynchronizer =new HistorySynchronizer(); + + HistorySynchronizer historySynchronizer =new HistorySynchronizer(); historySynchronizer.setId(historySynchronizer.generateId()); historySynchronizer.setSyncId(this.synchronizer.getId()); historySynchronizer.setSyncName(this.synchronizer.getName()); @@ -207,6 +220,123 @@ public class LdapUsersService extends AbstractSynchronizerService implements IS return userInfo; } + + public UserInfo buildUserInfoByFieldMap(HashMap attributeMap,String name,String nameInNamespace){ + UserInfo userInfo = new UserInfo(); + Map fieldMap = getFieldMap(Long.parseLong(synchronizer.getId())); + String []namePaths = name.replaceAll(",OU=" , "/") + .replaceAll("OU=" , "/") + .replaceAll(",ou=" , "/") + + .replaceAll("ou=" , "/") + .split("/"); + String namePah= "/"+rootOrganization.getOrgName(); + for(int i = namePaths.length -1 ; i >= 0 ; i --) { + namePah = namePah + "/" + namePaths[i]; + } + + namePah = namePah.substring(0, namePah.length()); + String deptNamePath= namePah.substring(0, namePah.lastIndexOf("/")); + _logger.info("deptNamePath " + deptNamePath); + + Organizations deptOrg = orgsNamePathMap.get(deptNamePath); + + userInfo.setLdapDn(nameInNamespace); + userInfo.setId(userInfo.generateId()); + userInfo.setUserState("RESIDENT"); + userInfo.setUserType("EMPLOYEE"); + userInfo.setTimeZone("Asia/Shanghai"); + userInfo.setStatus(1); + userInfo.setInstId(this.synchronizer.getInstId()); + + for (Map.Entry entry : fieldMap.entrySet()) { + String targetAttr = entry.getKey(); + String sourceAttr = entry.getValue(); + String value = null; + try { + + if(!attributeMap.keySet().contains(sourceAttr.toLowerCase())){ + value = (String) getFieldValue(deptOrg, sourceAttr); + if(value!=null){ + setFieldValue(userInfo,targetAttr,value); + continue; + } + } + value = LdapUtils.getAttributeStringValue(sourceAttr,attributeMap); + if(targetAttr.equals("formattedName")){ + userInfo.setFormattedName(LdapUtils.getAttributeStringValue(InetOrgPerson.SN,attributeMap)+ + LdapUtils.getAttributeStringValue(InetOrgPerson.GIVENNAME,attributeMap)); + continue; + } + //只配置 username 到 uid 的映射关系 + ///只配置 windowsAccount 到 uid 的映射关系 + if (targetAttr.equals("username") || targetAttr.equals("windowsAccount")) { + if (sourceAttr.equals("uid") && StringUtils.isBlank(value)) { + value = LdapUtils.getAttributeStringValue(InetOrgPerson.CN,attributeMap); + }else{ + value = LdapUtils.getAttributeStringValue(InetOrgPerson.UID,attributeMap); + } + //只配置 nickName 到 initials 的映射关系 + //只配置 nameZhShortSpell 到 initials 的映射关系 + } else if (targetAttr.equals("nickName") || targetAttr.equals("nameZhShortSpell")) { + if (sourceAttr.equals("initials") && StringUtils.isBlank(value)) { + value = LdapUtils.getAttributeStringValue(InetOrgPerson.SN,attributeMap) + + LdapUtils.getAttributeStringValue(InetOrgPerson.GIVENNAME,attributeMap); + }else{ + value = LdapUtils.getAttributeStringValue(InetOrgPerson.INITIALS,attributeMap); + } + + //只配置 displayName 到 displayName 的映射关系 + } else if (targetAttr.equals("displayName")) { + if (sourceAttr.equals("displayName") && StringUtils.isBlank(value)) { + value = LdapUtils.getAttributeStringValue(InetOrgPerson.SN,attributeMap) + + LdapUtils.getAttributeStringValue(InetOrgPerson.GIVENNAME,attributeMap); + }else { + value = LdapUtils.getAttributeStringValue(InetOrgPerson.DISPLAYNAME,attributeMap); + } + } else if (targetAttr.equals("mobile")) { + if (sourceAttr.equals("mobile") && StringUtils.isBlank(value)) { + value = (String) getFieldValue(userInfo,"id"); + }else { + value = LdapUtils.getAttributeStringValue(InetOrgPerson.MOBILE,attributeMap); + } + } + + setFieldValue(userInfo, targetAttr,value); + }catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } catch (NamingException e) { + throw new RuntimeException(e); + } + + } + HistorySynchronizer historySynchronizer =new HistorySynchronizer(); + historySynchronizer.setId(historySynchronizer.generateId()); + historySynchronizer.setSyncId(this.synchronizer.getId()); + historySynchronizer.setSyncName(this.synchronizer.getName()); + historySynchronizer.setObjectId(userInfo.getId()); + historySynchronizer.setObjectName(userInfo.getUsername()); + historySynchronizer.setObjectType(Organizations.class.getSimpleName()); + historySynchronizer.setInstId(synchronizer.getInstId()); + historySynchronizer.setResult("success"); + this.historySynchronizerService.insert(historySynchronizer); + + return userInfo; + } + + public Map getFieldMap(Long jobId){ + Map userFieldMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取用户属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == USER_TYPE.intValue()){ + userFieldMap.put(element.getTargetField(), element.getSourceField()); + } + } + return userFieldMap; + } + public LdapUtils getLdapUtils() { return ldapUtils; @@ -215,5 +345,12 @@ public class LdapUsersService extends AbstractSynchronizerService implements IS public void setLdapUtils(LdapUtils ldapUtils) { this.ldapUtils = ldapUtils; } - + + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } } diff --git a/maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/dromara/maxkey/synchronizer/workweixin/WorkweixinOrganizationService.java b/maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/dromara/maxkey/synchronizer/workweixin/WorkweixinOrganizationService.java index 3a76acf52..1f8206f63 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/dromara/maxkey/synchronizer/workweixin/WorkweixinOrganizationService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/dromara/maxkey/synchronizer/workweixin/WorkweixinOrganizationService.java @@ -22,20 +22,32 @@ import org.dromara.maxkey.entity.SynchroRelated; import org.dromara.maxkey.entity.idm.Organizations; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; import org.dromara.maxkey.synchronizer.workweixin.entity.WorkWeixinDepts; import org.dromara.maxkey.synchronizer.workweixin.entity.WorkWeixinDeptsResponse; import org.dromara.maxkey.util.JsonUtils; import org.dromara.maxkey.web.HttpRequestAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.*; + @Service public class WorkweixinOrganizationService extends AbstractSynchronizerService implements ISynchronizerService{ static final Logger _logger = LoggerFactory.getLogger(WorkweixinOrganizationService.class); String access_token; - + @Autowired + private SyncJobConfigFieldService syncJobConfigFieldService; + private static final Integer ORG_TYPE = 2; static String DEPTS_URL="https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=%s"; static long ROOT_DEPT_ID = 1; @@ -58,8 +70,11 @@ public class WorkweixinOrganizationService extends AbstractSynchronizerService i SynchroRelated synchroRelated = synchroRelatedService.findByOriginId( this.synchronizer,dept.getId() + "",Organizations.CLASS_TYPE ); - - Organizations organization = buildOrganization(dept); + //Parent + SynchroRelated synchroRelatedParent = + synchroRelatedService.findByOriginId( + this.synchronizer,dept.getParentid() + "",Organizations.CLASS_TYPE); + Organizations organization = buildOrgByFiledMap(dept,synchroRelatedParent); if(synchroRelated == null) { organization.setId(organization.generateId()); organizationsService.insert(organization); @@ -109,11 +124,8 @@ public class WorkweixinOrganizationService extends AbstractSynchronizerService i return deptsResponse; } - public Organizations buildOrganization(WorkWeixinDepts dept) { - //Parent - SynchroRelated synchroRelatedParent = - synchroRelatedService.findByOriginId( - this.synchronizer,dept.getParentid() + "",Organizations.CLASS_TYPE); + public Organizations buildOrganization(WorkWeixinDepts dept,SynchroRelated synchroRelatedParent) { + Organizations org = new Organizations(); org.setOrgName(dept.getName()); org.setOrgCode(dept.getId()+""); @@ -126,6 +138,57 @@ public class WorkweixinOrganizationService extends AbstractSynchronizerService i return org; } + + public Organizations buildOrgByFiledMap(WorkWeixinDepts dept, SynchroRelated synchroRelatedParent){ + Organizations org = new Organizations(); + //fieldMap + Map fieldMap = getFieldMap(Long.parseLong(synchronizer.getId())); + + + for (Map.Entry entry : fieldMap.entrySet()) { + String orgProperty = entry.getKey(); + String sourceProperty = entry.getValue(); + try { + Object sourceValue = null; + + if (hasField(dept.getClass(), sourceProperty)) { + sourceValue = getFieldValue(dept, sourceProperty); + } + else if (synchroRelatedParent != null && hasField(SynchroRelated.class, sourceProperty)) { + sourceValue = getFieldValue(synchroRelatedParent, sourceProperty); + } + if (sourceValue != null) { + setFieldValue(org, orgProperty, sourceValue); + } + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + org.setInstId(this.synchronizer.getInstId()); + org.setStatus(ConstsStatus.ACTIVE); + org.setDescription("WorkWeixin"); + org.setType("department"); + return org; + + } + + public Map getFieldMap(Long jobId){ + Map filedMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取组织属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == ORG_TYPE.intValue()){ + filedMap.put(element.getTargetField(), element.getSourceField()); + } + } + return filedMap; + } + + + + + public String getAccess_token() { return access_token; } @@ -134,4 +197,11 @@ public class WorkweixinOrganizationService extends AbstractSynchronizerService i this.access_token = access_token; } + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } } diff --git a/maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/dromara/maxkey/synchronizer/workweixin/WorkweixinUsersService.java b/maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/dromara/maxkey/synchronizer/workweixin/WorkweixinUsersService.java index 62f718f0e..3ee68a0b7 100644 --- a/maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/dromara/maxkey/synchronizer/workweixin/WorkweixinUsersService.java +++ b/maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/dromara/maxkey/synchronizer/workweixin/WorkweixinUsersService.java @@ -17,25 +17,36 @@ package org.dromara.maxkey.synchronizer.workweixin; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.dromara.maxkey.constants.ConstsStatus; import org.dromara.maxkey.entity.SynchroRelated; import org.dromara.maxkey.entity.idm.UserInfo; import org.dromara.maxkey.synchronizer.AbstractSynchronizerService; import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.entity.SyncJobConfigField; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; import org.dromara.maxkey.synchronizer.workweixin.entity.WorkWeixinUsers; import org.dromara.maxkey.synchronizer.workweixin.entity.WorkWeixinUsersResponse; import org.dromara.maxkey.util.JsonUtils; import org.dromara.maxkey.web.HttpRequestAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import static org.dromara.maxkey.synchronizer.utils.FieldUtil.*; + @Service public class WorkweixinUsersService extends AbstractSynchronizerService implements ISynchronizerService{ - static final Logger _logger = LoggerFactory.getLogger(WorkweixinUsersService.class); - + final static Logger _logger = LoggerFactory.getLogger(WorkweixinUsersService.class); + + @Autowired + public SyncJobConfigFieldService syncJobConfigFieldService; + private static final Integer USER_TYPE = 1; String access_token; static String USERS_URL="https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token=%s&department_id=%s&fetch_child=0"; @@ -53,7 +64,7 @@ public class WorkweixinUsersService extends AbstractSynchronizerService implemen _logger.trace("response : " + responseBody); for(WorkWeixinUsers user : usersResponse.getUserlist()) { - UserInfo userInfo = buildUserInfo(user); + UserInfo userInfo = buildUserInfoByFiledMap(user); _logger.debug("userInfo : " + userInfo); userInfo.setPassword(userInfo.getUsername() + UserInfo.DEFAULT_PASSWORD_SUFFIX); userInfoService.saveOrUpdate(userInfo); @@ -113,7 +124,59 @@ public class WorkweixinUsersService extends AbstractSynchronizerService implemen return userInfo; } + public UserInfo buildUserInfoByFiledMap(WorkWeixinUsers user){ + UserInfo userInfo = new UserInfo(); + Map fieldMap = getFieldMap(Long.parseLong(synchronizer.getId())); + for (Map.Entry entry : fieldMap.entrySet()) { + + String userInfoProperty = entry.getKey(); + String sourceProperty = entry.getValue(); + + try { + Object sourceValue = null; + if(sourceProperty.equals("status")){ + userInfo.setStatus(user.getStatus() == 1?ConstsStatus.ACTIVE:ConstsStatus.INACTIVE); + continue; + } + if (hasField(user.getClass(), sourceProperty)) { + sourceValue = getFieldValue(user, sourceProperty); + } + if (sourceValue != null) { + setFieldValue(userInfo, userInfoProperty, sourceValue); + } + + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + userInfo.setUserType("EMPLOYEE"); + userInfo.setUserState("RESIDENT"); + userInfo.setInstId(this.synchronizer.getInstId()); + return userInfo; + } + + public Map getFieldMap(Long jobId){ + Map userFieldMap = new HashMap<>(); + //根据job id查询属性映射表 + List syncJobConfigFieldList = syncJobConfigFieldService.findByJobId(jobId); + //获取用户属性映射 + for(SyncJobConfigField element:syncJobConfigFieldList){ + if(Integer.parseInt(element.getObjectType()) == USER_TYPE.intValue()){ + userFieldMap.put(element.getTargetField(), element.getSourceField()); + } + } + return userFieldMap; + } + public void setAccess_token(String access_token) { this.access_token = access_token; } + public SyncJobConfigFieldService getSyncJobConfigFieldService() { + return syncJobConfigFieldService; + } + + public void setSyncJobConfigFieldService(SyncJobConfigFieldService syncJobConfigFieldService) { + this.syncJobConfigFieldService = syncJobConfigFieldService; + } } diff --git a/maxkey-synchronizers/maxkey-synchronizer/src/main/java/org/dromara/maxkey/synchronizer/service/SyncJobConfigFieldService.java b/maxkey-synchronizers/maxkey-synchronizer/src/main/java/org/dromara/maxkey/synchronizer/service/SyncJobConfigFieldService.java new file mode 100644 index 000000000..136c9349f --- /dev/null +++ b/maxkey-synchronizers/maxkey-synchronizer/src/main/java/org/dromara/maxkey/synchronizer/service/SyncJobConfigFieldService.java @@ -0,0 +1,43 @@ +package org.dromara.maxkey.synchronizer.service; + +import org.dromara.maxkey.entity.SyncJobConfigField; + +import org.dromara.maxkey.persistence.mapper.SyncJobConfigFieldMapper; +import org.dromara.mybatis.jpa.JpaService; +import org.springframework.stereotype.Service; + +import java.sql.Types; +import java.util.ArrayList; +import java.util.List; + +@Service +public class SyncJobConfigFieldService extends JpaService { + public SyncJobConfigFieldService() { + super(SyncJobConfigFieldMapper.class); + } + @Override + public SyncJobConfigFieldMapper getMapper() { + return (SyncJobConfigFieldMapper)super.getMapper(); + } + + public List findByJobIdAndObjectType(Long jobId, String objectType) { + + return getMapper().findByJobIdAndObjectType(jobId,objectType); + } + + public void deleteFieldMapById(Long id){ + ArrayList ids = new ArrayList<>(); + ids.add(String.valueOf(id)); + super.deleteBatch(ids); + } + + public List findByJobId(Long jobId) { + List list = find(" jobid = ?", + new Object[]{jobId}, + new int[]{Types.BIGINT}); + return list; + + } + + +} diff --git a/maxkey-synchronizers/maxkey-synchronizer/src/main/java/org/dromara/maxkey/synchronizer/utils/FieldUtil.java b/maxkey-synchronizers/maxkey-synchronizer/src/main/java/org/dromara/maxkey/synchronizer/utils/FieldUtil.java new file mode 100644 index 000000000..5ec007371 --- /dev/null +++ b/maxkey-synchronizers/maxkey-synchronizer/src/main/java/org/dromara/maxkey/synchronizer/utils/FieldUtil.java @@ -0,0 +1,108 @@ +package org.dromara.maxkey.synchronizer.utils; + +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + + +public class FieldUtil { + + public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class clazz = obj.getClass(); + + String setterMethodName = "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); + String getterMethodName = "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); + Method getterMethod = clazz.getMethod(getterMethodName); + Class fieldType = getterMethod.getReturnType(); + + Object convertedValue = convertValueToFieldType(value, fieldType); + + Method setterMethod = clazz.getMethod(setterMethodName, fieldType); + setterMethod.invoke(obj, convertedValue); + } + + public static Object getFieldValue(Object obj, String fieldName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class clazz = obj.getClass(); + + String getterMethodName = "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); + Method method = clazz.getMethod(getterMethodName); + + return method.invoke(obj); + } + + public static boolean hasField(Class clazz, String fieldName) { + Field[] declaredFields = clazz.getDeclaredFields(); + for (Field field : declaredFields) { + if (field.getName().equals(fieldName)) { + return true; + } + } + return false; + } + + public static Object convertValueToFieldType(Object value, Class fieldType) { + if (fieldType.isInstance(value)) { + return value; + } + + if (fieldType == Integer.class || fieldType == int.class) { + if (value instanceof Boolean) { + return (Boolean) value ? 1 : 0; + } + return Integer.parseInt(value.toString()); + } else if (fieldType == Long.class || fieldType == long.class) { + return Long.parseLong(value.toString()); + } else if (fieldType == Double.class || fieldType == double.class) { + return Double.parseDouble(value.toString()); + } else if (fieldType == Boolean.class || fieldType == boolean.class) { + return "1".equals(value.toString()) || Boolean.parseBoolean(value.toString()); + } else if (fieldType == String.class) { + return value.toString(); + } else if (fieldType == DateTime.class) { + DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd"); + DateTime dateTime; + if (value instanceof Long) { + dateTime = new DateTime((Long) value); + } else if (value instanceof String) { + dateTime = DateTime.parse((String) value); + }else { + dateTime = new DateTime(value); + } + return dateTime.toString(formatter); + } + throw new IllegalArgumentException("Unsupported field type: " + fieldType); + } + + public static boolean areFieldsEqual(Object obj1, Object obj2) { + if (obj1 == null || obj2 == null) { + return false; + } + if (!obj1.getClass().equals(obj2.getClass())) { + return false; + } + + Field[] fields = obj1.getClass().getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + try { + Object value1 = field.get(obj1); + Object value2 = field.get(obj2); + if (value1 == null) { + if (value2 != null) { + return false; + } + } else if (!value1.equals(value2)) { + return false; + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + return false; + } + } + return true; + } +} diff --git a/maxkey-web-apis/maxkey-web-api-rest/src/main/java/org/dromara/maxkey/web/apis/identity/rest/RestOrganizationController.java b/maxkey-web-apis/maxkey-web-api-rest/src/main/java/org/dromara/maxkey/web/apis/identity/rest/RestOrganizationController.java index dca25686a..2b55dfcd9 100644 --- a/maxkey-web-apis/maxkey-web-api-rest/src/main/java/org/dromara/maxkey/web/apis/identity/rest/RestOrganizationController.java +++ b/maxkey-web-apis/maxkey-web-api-rest/src/main/java/org/dromara/maxkey/web/apis/identity/rest/RestOrganizationController.java @@ -100,4 +100,6 @@ public class RestOrganizationController { _logger.debug("Organizations {}" , org); return new Message<>(organizationsService.fetchPageResults(org)); } + + } diff --git a/maxkey-web-frontend/maxkey-web-app/package-lock.json b/maxkey-web-frontend/maxkey-web-app/package-lock.json index 8033fc05f..34e76517e 100644 --- a/maxkey-web-frontend/maxkey-web-app/package-lock.json +++ b/maxkey-web-frontend/maxkey-web-app/package-lock.json @@ -34,6 +34,7 @@ "ngx-cookie-service": "^13.2.0", "ngx-tinymce": "^13.0.0", "ngx-ueditor": "^13.0.0", + "npm": "^8.5.5", "rxjs": "~7.5.0", "screenfull": "^6.0.1", "tslib": "^2.3.0", @@ -11102,7 +11103,6 @@ "resolved": "https://registry.npmmirror.com/husky/-/husky-7.0.4.tgz", "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", "dev": true, - "license": "MIT", "bin": { "husky": "lib/bin.js" }, @@ -14600,6 +14600,168 @@ "dev": true, "license": "MIT" }, + "node_modules/npm": { + "version": "8.5.5", + "resolved": "https://registry.npmmirror.com/npm/-/npm-8.5.5.tgz", + "integrity": "sha512-a1vl26nokCNlD+my/iNYmOUPx/hpYR4ZyZk8gb7/A2XXtrPZf2gTSJOnVjS77jQS+BSfIVQpipZwXWCL0+5wzg==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/ci-detect", + "@npmcli/config", + "@npmcli/map-workspaces", + "@npmcli/package-json", + "@npmcli/run-script", + "abbrev", + "ansicolors", + "ansistyles", + "archy", + "cacache", + "chalk", + "chownr", + "cli-columns", + "cli-table3", + "columnify", + "fastest-levenshtein", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmhook", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minipass", + "minipass-pipeline", + "mkdirp", + "mkdirp-infer-owner", + "ms", + "node-gyp", + "nopt", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "npmlog", + "opener", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "read-package-json", + "read-package-json-fast", + "readdir-scoped-modules", + "rimraf", + "semver", + "ssri", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which", + "write-file-atomic" + ], + "workspaces": [ + "docs", + "workspaces/*" + ], + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^5.0.3", + "@npmcli/ci-detect": "^2.0.0", + "@npmcli/config": "^4.0.1", + "@npmcli/map-workspaces": "^2.0.2", + "@npmcli/package-json": "^1.0.1", + "@npmcli/run-script": "^3.0.1", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "archy": "~1.0.0", + "cacache": "^16.0.2", + "chalk": "^4.1.2", + "chownr": "^2.0.0", + "cli-columns": "^4.0.0", + "cli-table3": "^0.6.1", + "columnify": "^1.6.0", + "fastest-levenshtein": "^1.0.12", + "glob": "^7.2.0", + "graceful-fs": "^4.2.9", + "hosted-git-info": "^5.0.0", + "ini": "^2.0.0", + "init-package-json": "^3.0.1", + "is-cidr": "^4.0.2", + "json-parse-even-better-errors": "^2.3.1", + "libnpmaccess": "^6.0.2", + "libnpmdiff": "^4.0.2", + "libnpmexec": "^4.0.2", + "libnpmfund": "^3.0.1", + "libnpmhook": "^8.0.2", + "libnpmorg": "^4.0.2", + "libnpmpack": "^4.0.2", + "libnpmpublish": "^6.0.2", + "libnpmsearch": "^5.0.2", + "libnpmteam": "^4.0.2", + "libnpmversion": "^3.0.1", + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "ms": "^2.1.2", + "node-gyp": "^9.0.0", + "nopt": "^5.0.0", + "npm-audit-report": "^2.1.5", + "npm-install-checks": "^4.0.0", + "npm-package-arg": "^9.0.1", + "npm-pick-manifest": "^7.0.0", + "npm-profile": "^6.0.2", + "npm-registry-fetch": "^13.0.1", + "npm-user-validate": "^1.0.1", + "npmlog": "^6.0.1", + "opener": "^1.5.2", + "pacote": "^13.0.5", + "parse-conflict-json": "^2.0.1", + "proc-log": "^2.0.0", + "qrcode-terminal": "^0.12.0", + "read": "~1.0.7", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "ssri": "^8.0.1", + "tar": "^6.1.11", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^1.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^2.0.2", + "write-file-atomic": "^4.0.1" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, "node_modules/npm-bundled": { "version": "1.1.2", "resolved": "https://registry.npmmirror.com/npm-bundled/-/npm-bundled-1.1.2.tgz", @@ -14708,6 +14870,2023 @@ "node": ">=8" } }, + "node_modules/npm/node_modules/@gar/promisify": { + "version": "1.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "5.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/map-workspaces": "^2.0.0", + "@npmcli/metavuln-calculator": "^3.0.1", + "@npmcli/move-file": "^1.1.0", + "@npmcli/name-from-folder": "^1.0.1", + "@npmcli/node-gyp": "^1.0.3", + "@npmcli/package-json": "^1.0.1", + "@npmcli/run-script": "^3.0.0", + "bin-links": "^3.0.0", + "cacache": "^16.0.0", + "common-ancestor-path": "^1.0.1", + "json-parse-even-better-errors": "^2.3.1", + "json-stringify-nice": "^1.1.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "nopt": "^5.0.0", + "npm-install-checks": "^4.0.0", + "npm-package-arg": "^9.0.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.0", + "npmlog": "^6.0.1", + "pacote": "^13.0.5", + "parse-conflict-json": "^2.0.1", + "proc-log": "^2.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.1", + "read-package-json-fast": "^2.0.2", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "ssri": "^8.0.1", + "treeverse": "^1.0.4", + "walk-up-path": "^1.0.0" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/@npmcli/ci-detect": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "4.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/map-workspaces": "^2.0.1", + "ini": "^2.0.0", + "mkdirp-infer-owner": "^2.0.0", + "nopt": "^5.0.0", + "proc-log": "^2.0.0", + "read-package-json-fast": "^2.0.3", + "semver": "^7.3.5", + "walk-up-path": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/@npmcli/disparity-colors": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "ansi-styles": "^4.3.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^7.3.1", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "1.0.7", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "2.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^1.0.1", + "glob": "^7.2.0", + "minimatch": "^5.0.1", + "read-package-json-fast": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces/node_modules/brace-expansion": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces/node_modules/minimatch": { + "version": "5.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^16.0.0", + "json-parse-even-better-errors": "^2.3.1", + "pacote": "^13.0.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/@npmcli/move-file": { + "version": "1.1.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "1.0.3", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^2.3.1" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "1.3.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "infer-owner": "^1.0.4" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^1.0.3", + "@npmcli/promise-spawn": "^1.3.2", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/@tootallnate/once": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "1.1.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/agent-base": { + "version": "6.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/npm/node_modules/agentkeepalive": { + "version": "4.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/npm/node_modules/aggregate-error": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ansi-regex": { + "version": "5.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ansi-styles": { + "version": "4.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/ansicolors": { + "version": "0.3.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/ansistyles": { + "version": "0.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/are-we-there-yet": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/asap": { + "version": "2.0.6", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/bin-links": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^4.0.1", + "mkdirp-infer-owner": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0", + "read-cmd-shim": "^2.0.0", + "rimraf": "^3.0.0", + "write-file-atomic": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "2.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "1.1.11", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npm/node_modules/builtins": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/cacache": { + "version": "16.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.1.2", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^7.2.0", + "infer-owner": "^1.0.4", + "lru-cache": "^7.5.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/chalk": { + "version": "4.1.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "3.1.1", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "ip-regex": "^4.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/clean-stack": { + "version": "2.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/cli-columns": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/cli-table3": { + "version": "0.6.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "colors": "1.4.0" + } + }, + "node_modules/npm/node_modules/clone": { + "version": "1.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "4.1.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "mkdirp-infer-owner": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/color-convert": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/npm/node_modules/color-name": { + "version": "1.1.4", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/color-support": { + "version": "1.1.3", + "inBundle": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/npm/node_modules/colors": { + "version": "1.4.0", + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/npm/node_modules/columnify": { + "version": "1.6.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/concat-map": { + "version": "0.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/console-control-strings": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/debug": { + "version": "4.3.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/debuglog": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/defaults": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/npm/node_modules/delegates": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/depd": { + "version": "1.1.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/dezalgo": { + "version": "1.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/npm/node_modules/diff": { + "version": "5.0.0", + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/emoji-regex": { + "version": "8.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/encoding": { + "version": "0.1.13", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.12", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "2.1.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/fs.realpath": { + "version": "1.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/function-bind": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/gauge": { + "version": "4.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "7.2.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.9", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/has": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/npm/node_modules/has-flag": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/has-unicode": { + "version": "2.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.1.0", + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/humanize-ms": { + "version": "1.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.6.3", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "4.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npm/node_modules/indent-string": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/infer-owner": { + "version": "1.0.4", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/inflight": { + "version": "1.0.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/npm/node_modules/inherits": { + "version": "2.0.4", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/ini": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^9.0.0", + "promzard": "^0.3.0", + "read": "^1.0.7", + "read-package-json": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/ip": { + "version": "1.1.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/ip-regex": { + "version": "4.3.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "4.0.2", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "^3.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/is-core-module": { + "version": "2.8.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/npm/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/is-lambda": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/isexe": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff": { + "version": "5.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "4.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "6.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "minipass": "^3.1.1", + "npm-package-arg": "^9.0.1", + "npm-registry-fetch": "^13.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "4.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/disparity-colors": "^1.0.1", + "@npmcli/installed-package-contents": "^1.0.7", + "binary-extensions": "^2.2.0", + "diff": "^5.0.0", + "minimatch": "^3.0.4", + "npm-package-arg": "^9.0.1", + "pacote": "^13.0.5", + "tar": "^6.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "4.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^5.0.0", + "@npmcli/ci-detect": "^2.0.0", + "@npmcli/run-script": "^3.0.0", + "chalk": "^4.1.0", + "mkdirp-infer-owner": "^2.0.0", + "npm-package-arg": "^9.0.1", + "npmlog": "^6.0.1", + "pacote": "^13.0.5", + "proc-log": "^2.0.0", + "read": "^1.0.7", + "read-package-json-fast": "^2.0.2", + "walk-up-path": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/libnpmhook": { + "version": "8.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^13.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "4.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^13.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "4.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/run-script": "^3.0.0", + "npm-package-arg": "^9.0.1", + "pacote": "^13.0.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "6.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "normalize-package-data": "^4.0.0", + "npm-package-arg": "^9.0.1", + "npm-registry-fetch": "^13.0.0", + "semver": "^7.1.3", + "ssri": "^8.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "5.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^13.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "4.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^13.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^3.0.0", + "@npmcli/run-script": "^3.0.0", + "json-parse-even-better-errors": "^2.3.1", + "proc-log": "^2.0.0", + "semver": "^7.3.5", + "stringify-package": "^1.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "7.5.1", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "10.0.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.0.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.5.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.1.1", + "ssri": "^8.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "3.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "3.1.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "2.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-json-stream": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "1.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "2.1.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/mkdirp": { + "version": "1.0.4", + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/mkdirp-infer-owner": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "infer-owner": "^1.0.4", + "mkdirp": "^1.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "0.0.8", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/negotiator": { + "version": "0.6.3", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "9.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.22 || ^14.13 || >=16" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/normalize-package-data": { + "version": "4.0.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "2.1.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "1.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "4.0.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "9.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.2.0", + "ignore-walk": "^4.0.1", + "npm-bundled": "^1.1.2", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "7.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "6.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^13.0.0", + "proc-log": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "13.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "make-fetch-happen": "^10.0.3", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.1", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.0", + "proc-log": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "1.0.1", + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/npmlog": { + "version": "6.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.0", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/once": { + "version": "1.4.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/npm/node_modules/opener": { + "version": "1.5.2", + "inBundle": true, + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/pacote": { + "version": "13.0.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^3.0.1", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^4.0.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "2.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^2.3.1", + "just-diff": "^5.0.1", + "just-diff-apply": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/path-is-absolute": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/proc-log": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-inflight": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/promise-retry": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "0.3.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "1" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "1.0.7", + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/read-package-json": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.2.0", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/read-package-json-fast": { + "version": "2.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/readable-stream": { + "version": "3.6.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/rimraf": { + "version": "3.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.3.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/set-blocking": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "3.0.7", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.6.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "6.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/spdx-correct": { + "version": "3.1.1", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.3.0", + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.11", + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/ssri": { + "version": "8.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/string_decoder": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/npm/node_modules/string-width": { + "version": "4.2.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/stringify-package": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/strip-ansi": { + "version": "6.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "7.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "6.1.11", + "inBundle": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/treeverse": { + "version": "1.0.4", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/unique-filename": { + "version": "1.1.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/npm/node_modules/unique-slug": { + "version": "2.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.4", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "1.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/wcwidth": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/npm/node_modules/which": { + "version": "2.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/wide-align": { + "version": "1.1.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/npm/node_modules/wrappy": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/write-file-atomic": { + "version": "4.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/npm/node_modules/yallist": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC" + }, "node_modules/npmlog": { "version": "6.0.1", "resolved": "https://registry.npmmirror.com/npmlog/-/npmlog-6.0.1.tgz", @@ -32662,6 +34841,1478 @@ "integrity": "sha512-dxvWdI8gw6eAvk9BlPffgEoGfM7AdijoCwOEJge3e3ulT2XLgmU7KvvxprOaCu05Q1uGRHmOhHe1r6emZoKyFw==", "dev": true }, + "npm": { + "version": "8.5.5", + "resolved": "https://registry.npmmirror.com/npm/-/npm-8.5.5.tgz", + "integrity": "sha512-a1vl26nokCNlD+my/iNYmOUPx/hpYR4ZyZk8gb7/A2XXtrPZf2gTSJOnVjS77jQS+BSfIVQpipZwXWCL0+5wzg==", + "requires": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^5.0.3", + "@npmcli/ci-detect": "^2.0.0", + "@npmcli/config": "^4.0.1", + "@npmcli/map-workspaces": "^2.0.2", + "@npmcli/package-json": "^1.0.1", + "@npmcli/run-script": "^3.0.1", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "archy": "~1.0.0", + "cacache": "^16.0.2", + "chalk": "^4.1.2", + "chownr": "^2.0.0", + "cli-columns": "^4.0.0", + "cli-table3": "^0.6.1", + "columnify": "^1.6.0", + "fastest-levenshtein": "^1.0.12", + "glob": "^7.2.0", + "graceful-fs": "^4.2.9", + "hosted-git-info": "^5.0.0", + "ini": "^2.0.0", + "init-package-json": "^3.0.1", + "is-cidr": "^4.0.2", + "json-parse-even-better-errors": "^2.3.1", + "libnpmaccess": "^6.0.2", + "libnpmdiff": "^4.0.2", + "libnpmexec": "^4.0.2", + "libnpmfund": "^3.0.1", + "libnpmhook": "^8.0.2", + "libnpmorg": "^4.0.2", + "libnpmpack": "^4.0.2", + "libnpmpublish": "^6.0.2", + "libnpmsearch": "^5.0.2", + "libnpmteam": "^4.0.2", + "libnpmversion": "^3.0.1", + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "ms": "^2.1.2", + "node-gyp": "^9.0.0", + "nopt": "^5.0.0", + "npm-audit-report": "^2.1.5", + "npm-install-checks": "^4.0.0", + "npm-package-arg": "^9.0.1", + "npm-pick-manifest": "^7.0.0", + "npm-profile": "^6.0.2", + "npm-registry-fetch": "^13.0.1", + "npm-user-validate": "^1.0.1", + "npmlog": "^6.0.1", + "opener": "^1.5.2", + "pacote": "^13.0.5", + "parse-conflict-json": "^2.0.1", + "proc-log": "^2.0.0", + "qrcode-terminal": "^0.12.0", + "read": "~1.0.7", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "ssri": "^8.0.1", + "tar": "^6.1.11", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^1.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^2.0.2", + "write-file-atomic": "^4.0.1" + }, + "dependencies": { + "@gar/promisify": { + "version": "1.1.3", + "bundled": true + }, + "@isaacs/string-locale-compare": { + "version": "1.1.0", + "bundled": true + }, + "@npmcli/arborist": { + "version": "5.0.3", + "bundled": true, + "requires": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/map-workspaces": "^2.0.0", + "@npmcli/metavuln-calculator": "^3.0.1", + "@npmcli/move-file": "^1.1.0", + "@npmcli/name-from-folder": "^1.0.1", + "@npmcli/node-gyp": "^1.0.3", + "@npmcli/package-json": "^1.0.1", + "@npmcli/run-script": "^3.0.0", + "bin-links": "^3.0.0", + "cacache": "^16.0.0", + "common-ancestor-path": "^1.0.1", + "json-parse-even-better-errors": "^2.3.1", + "json-stringify-nice": "^1.1.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "nopt": "^5.0.0", + "npm-install-checks": "^4.0.0", + "npm-package-arg": "^9.0.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.0", + "npmlog": "^6.0.1", + "pacote": "^13.0.5", + "parse-conflict-json": "^2.0.1", + "proc-log": "^2.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.1", + "read-package-json-fast": "^2.0.2", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "ssri": "^8.0.1", + "treeverse": "^1.0.4", + "walk-up-path": "^1.0.0" + } + }, + "@npmcli/ci-detect": { + "version": "2.0.0", + "bundled": true + }, + "@npmcli/config": { + "version": "4.0.1", + "bundled": true, + "requires": { + "@npmcli/map-workspaces": "^2.0.1", + "ini": "^2.0.0", + "mkdirp-infer-owner": "^2.0.0", + "nopt": "^5.0.0", + "proc-log": "^2.0.0", + "read-package-json-fast": "^2.0.3", + "semver": "^7.3.5", + "walk-up-path": "^1.0.0" + } + }, + "@npmcli/disparity-colors": { + "version": "1.0.1", + "bundled": true, + "requires": { + "ansi-styles": "^4.3.0" + } + }, + "@npmcli/fs": { + "version": "1.1.0", + "bundled": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "3.0.0", + "bundled": true, + "requires": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^7.3.1", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + } + }, + "@npmcli/installed-package-contents": { + "version": "1.0.7", + "bundled": true, + "requires": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "@npmcli/map-workspaces": { + "version": "2.0.2", + "bundled": true, + "requires": { + "@npmcli/name-from-folder": "^1.0.1", + "glob": "^7.2.0", + "minimatch": "^5.0.1", + "read-package-json-fast": "^2.0.3" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "bundled": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@npmcli/metavuln-calculator": { + "version": "3.0.1", + "bundled": true, + "requires": { + "cacache": "^16.0.0", + "json-parse-even-better-errors": "^2.3.1", + "pacote": "^13.0.3", + "semver": "^7.3.5" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "bundled": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/name-from-folder": { + "version": "1.0.1", + "bundled": true + }, + "@npmcli/node-gyp": { + "version": "1.0.3", + "bundled": true + }, + "@npmcli/package-json": { + "version": "1.0.1", + "bundled": true, + "requires": { + "json-parse-even-better-errors": "^2.3.1" + } + }, + "@npmcli/promise-spawn": { + "version": "1.3.2", + "bundled": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "3.0.1", + "bundled": true, + "requires": { + "@npmcli/node-gyp": "^1.0.3", + "@npmcli/promise-spawn": "^1.3.2", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3" + } + }, + "@tootallnate/once": { + "version": "2.0.0", + "bundled": true + }, + "abbrev": { + "version": "1.1.1", + "bundled": true + }, + "agent-base": { + "version": "6.0.2", + "bundled": true, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.2.1", + "bundled": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "bundled": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ansi-regex": { + "version": "5.0.1", + "bundled": true + }, + "ansi-styles": { + "version": "4.3.0", + "bundled": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true + }, + "aproba": { + "version": "2.0.0", + "bundled": true + }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "are-we-there-yet": { + "version": "3.0.0", + "bundled": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "asap": { + "version": "2.0.6", + "bundled": true + }, + "balanced-match": { + "version": "1.0.2", + "bundled": true + }, + "bin-links": { + "version": "3.0.0", + "bundled": true, + "requires": { + "cmd-shim": "^4.0.1", + "mkdirp-infer-owner": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0", + "read-cmd-shim": "^2.0.0", + "rimraf": "^3.0.0", + "write-file-atomic": "^4.0.0" + } + }, + "binary-extensions": { + "version": "2.2.0", + "bundled": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "builtins": { + "version": "1.0.3", + "bundled": true + }, + "cacache": { + "version": "16.0.2", + "bundled": true, + "requires": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.1.2", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^7.2.0", + "infer-owner": "^1.0.4", + "lru-cache": "^7.5.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + } + }, + "chalk": { + "version": "4.1.2", + "bundled": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chownr": { + "version": "2.0.0", + "bundled": true + }, + "cidr-regex": { + "version": "3.1.1", + "bundled": true, + "requires": { + "ip-regex": "^4.1.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "bundled": true + }, + "cli-columns": { + "version": "4.0.0", + "bundled": true, + "requires": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + } + }, + "cli-table3": { + "version": "0.6.1", + "bundled": true, + "requires": { + "colors": "1.4.0", + "string-width": "^4.2.0" + } + }, + "clone": { + "version": "1.0.4", + "bundled": true + }, + "cmd-shim": { + "version": "4.1.0", + "bundled": true, + "requires": { + "mkdirp-infer-owner": "^2.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "bundled": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "bundled": true + }, + "color-support": { + "version": "1.1.3", + "bundled": true + }, + "colors": { + "version": "1.4.0", + "bundled": true, + "optional": true + }, + "columnify": { + "version": "1.6.0", + "bundled": true, + "requires": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + } + }, + "common-ancestor-path": { + "version": "1.0.1", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "debug": { + "version": "4.3.3", + "bundled": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "bundled": true + } + } + }, + "debuglog": { + "version": "1.0.1", + "bundled": true + }, + "defaults": { + "version": "1.0.3", + "bundled": true, + "requires": { + "clone": "^1.0.2" + } + }, + "delegates": { + "version": "1.0.0", + "bundled": true + }, + "depd": { + "version": "1.1.2", + "bundled": true + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "diff": { + "version": "5.0.0", + "bundled": true + }, + "emoji-regex": { + "version": "8.0.0", + "bundled": true + }, + "encoding": { + "version": "0.1.13", + "bundled": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + } + }, + "env-paths": { + "version": "2.2.1", + "bundled": true + }, + "err-code": { + "version": "2.0.3", + "bundled": true + }, + "fastest-levenshtein": { + "version": "1.0.12", + "bundled": true + }, + "fs-minipass": { + "version": "2.1.0", + "bundled": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true + }, + "gauge": { + "version": "4.0.3", + "bundled": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "glob": { + "version": "7.2.0", + "bundled": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.9", + "bundled": true + }, + "has": { + "version": "1.0.3", + "bundled": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "bundled": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hosted-git-info": { + "version": "5.0.0", + "bundled": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "bundled": true + }, + "http-proxy-agent": { + "version": "5.0.0", + "bundled": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "bundled": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "humanize-ms": { + "version": "1.2.1", + "bundled": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.6.3", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ignore-walk": { + "version": "4.0.1", + "bundled": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "indent-string": { + "version": "4.0.0", + "bundled": true + }, + "infer-owner": { + "version": "1.0.4", + "bundled": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true + }, + "ini": { + "version": "2.0.0", + "bundled": true + }, + "init-package-json": { + "version": "3.0.1", + "bundled": true, + "requires": { + "npm-package-arg": "^9.0.0", + "promzard": "^0.3.0", + "read": "^1.0.7", + "read-package-json": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^3.0.0" + } + }, + "ip": { + "version": "1.1.5", + "bundled": true + }, + "ip-regex": { + "version": "4.3.0", + "bundled": true + }, + "is-cidr": { + "version": "4.0.2", + "bundled": true, + "requires": { + "cidr-regex": "^3.1.1" + } + }, + "is-core-module": { + "version": "2.8.1", + "bundled": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "bundled": true + }, + "is-lambda": { + "version": "1.0.1", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "bundled": true + }, + "json-stringify-nice": { + "version": "1.1.4", + "bundled": true + }, + "jsonparse": { + "version": "1.3.1", + "bundled": true + }, + "just-diff": { + "version": "5.0.1", + "bundled": true + }, + "just-diff-apply": { + "version": "4.0.1", + "bundled": true + }, + "libnpmaccess": { + "version": "6.0.2", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "minipass": "^3.1.1", + "npm-package-arg": "^9.0.1", + "npm-registry-fetch": "^13.0.0" + } + }, + "libnpmdiff": { + "version": "4.0.2", + "bundled": true, + "requires": { + "@npmcli/disparity-colors": "^1.0.1", + "@npmcli/installed-package-contents": "^1.0.7", + "binary-extensions": "^2.2.0", + "diff": "^5.0.0", + "minimatch": "^3.0.4", + "npm-package-arg": "^9.0.1", + "pacote": "^13.0.5", + "tar": "^6.1.0" + } + }, + "libnpmexec": { + "version": "4.0.2", + "bundled": true, + "requires": { + "@npmcli/arborist": "^5.0.0", + "@npmcli/ci-detect": "^2.0.0", + "@npmcli/run-script": "^3.0.0", + "chalk": "^4.1.0", + "mkdirp-infer-owner": "^2.0.0", + "npm-package-arg": "^9.0.1", + "npmlog": "^6.0.1", + "pacote": "^13.0.5", + "proc-log": "^2.0.0", + "read": "^1.0.7", + "read-package-json-fast": "^2.0.2", + "walk-up-path": "^1.0.0" + } + }, + "libnpmfund": { + "version": "3.0.1", + "bundled": true, + "requires": { + "@npmcli/arborist": "^5.0.0" + } + }, + "libnpmhook": { + "version": "8.0.2", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^13.0.0" + } + }, + "libnpmorg": { + "version": "4.0.2", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^13.0.0" + } + }, + "libnpmpack": { + "version": "4.0.2", + "bundled": true, + "requires": { + "@npmcli/run-script": "^3.0.0", + "npm-package-arg": "^9.0.1", + "pacote": "^13.0.5" + } + }, + "libnpmpublish": { + "version": "6.0.2", + "bundled": true, + "requires": { + "normalize-package-data": "^4.0.0", + "npm-package-arg": "^9.0.1", + "npm-registry-fetch": "^13.0.0", + "semver": "^7.1.3", + "ssri": "^8.0.1" + } + }, + "libnpmsearch": { + "version": "5.0.2", + "bundled": true, + "requires": { + "npm-registry-fetch": "^13.0.0" + } + }, + "libnpmteam": { + "version": "4.0.2", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^13.0.0" + } + }, + "libnpmversion": { + "version": "3.0.1", + "bundled": true, + "requires": { + "@npmcli/git": "^3.0.0", + "@npmcli/run-script": "^3.0.0", + "json-parse-even-better-errors": "^2.3.1", + "proc-log": "^2.0.0", + "semver": "^7.3.5", + "stringify-package": "^1.0.1" + } + }, + "lru-cache": { + "version": "7.5.1", + "bundled": true + }, + "make-fetch-happen": { + "version": "10.0.6", + "bundled": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.0.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.5.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.1.1", + "ssri": "^8.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minipass": { + "version": "3.1.6", + "bundled": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "bundled": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "2.0.3", + "bundled": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "minipass-flush": { + "version": "1.0.5", + "bundled": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "bundled": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "bundled": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "bundled": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "bundled": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "bundled": true + }, + "mkdirp-infer-owner": { + "version": "2.0.0", + "bundled": true, + "requires": { + "chownr": "^2.0.0", + "infer-owner": "^1.0.4", + "mkdirp": "^1.0.3" + } + }, + "ms": { + "version": "2.1.3", + "bundled": true + }, + "mute-stream": { + "version": "0.0.8", + "bundled": true + }, + "negotiator": { + "version": "0.6.3", + "bundled": true + }, + "node-gyp": { + "version": "9.0.0", + "bundled": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + } + }, + "nopt": { + "version": "5.0.0", + "bundled": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "4.0.0", + "bundled": true, + "requires": { + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "npm-audit-report": { + "version": "2.1.5", + "bundled": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "npm-bundled": { + "version": "1.1.2", + "bundled": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-install-checks": { + "version": "4.0.0", + "bundled": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true + }, + "npm-package-arg": { + "version": "9.0.1", + "bundled": true, + "requires": { + "hosted-git-info": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "4.0.0", + "bundled": true, + "requires": { + "glob": "^7.2.0", + "ignore-walk": "^4.0.1", + "npm-bundled": "^1.1.2", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "7.0.0", + "bundled": true, + "requires": { + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + } + }, + "npm-profile": { + "version": "6.0.2", + "bundled": true, + "requires": { + "npm-registry-fetch": "^13.0.0", + "proc-log": "^2.0.0" + } + }, + "npm-registry-fetch": { + "version": "13.0.1", + "bundled": true, + "requires": { + "make-fetch-happen": "^10.0.3", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.1", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.0", + "proc-log": "^2.0.0" + } + }, + "npm-user-validate": { + "version": "1.0.1", + "bundled": true + }, + "npmlog": { + "version": "6.0.1", + "bundled": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.0", + "set-blocking": "^2.0.0" + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.5.2", + "bundled": true + }, + "p-map": { + "version": "4.0.0", + "bundled": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "pacote": { + "version": "13.0.5", + "bundled": true, + "requires": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^3.0.1", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^4.0.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.11" + } + }, + "parse-conflict-json": { + "version": "2.0.1", + "bundled": true, + "requires": { + "json-parse-even-better-errors": "^2.3.1", + "just-diff": "^5.0.1", + "just-diff-apply": "^4.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "proc-log": { + "version": "2.0.0", + "bundled": true + }, + "promise-all-reject-late": { + "version": "1.0.1", + "bundled": true + }, + "promise-call-limit": { + "version": "1.0.1", + "bundled": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true + }, + "promise-retry": { + "version": "2.0.1", + "bundled": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "promzard": { + "version": "0.3.0", + "bundled": true, + "requires": { + "read": "1" + } + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true + }, + "read": { + "version": "1.0.7", + "bundled": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "read-cmd-shim": { + "version": "2.0.0", + "bundled": true + }, + "read-package-json": { + "version": "5.0.0", + "bundled": true, + "requires": { + "glob": "^7.2.0", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "read-package-json-fast": { + "version": "2.0.3", + "bundled": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "retry": { + "version": "0.12.0", + "bundled": true + }, + "rimraf": { + "version": "3.0.2", + "bundled": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "semver": { + "version": "7.3.5", + "bundled": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "bundled": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.7", + "bundled": true + }, + "smart-buffer": { + "version": "4.2.0", + "bundled": true + }, + "socks": { + "version": "2.6.2", + "bundled": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "6.1.1", + "bundled": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + } + }, + "spdx-correct": { + "version": "3.1.1", + "bundled": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "bundled": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "bundled": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.11", + "bundled": true + }, + "ssri": { + "version": "8.0.1", + "bundled": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "bundled": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "version": "4.2.3", + "bundled": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "stringify-package": { + "version": "1.0.1", + "bundled": true + }, + "strip-ansi": { + "version": "6.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "bundled": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tar": { + "version": "6.1.11", + "bundled": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true + }, + "treeverse": { + "version": "1.0.4", + "bundled": true + }, + "unique-filename": { + "version": "1.1.1", + "bundled": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "bundled": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "bundled": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "walk-up-path": { + "version": "1.0.0", + "bundled": true + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "which": { + "version": "2.0.2", + "bundled": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "bundled": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write-file-atomic": { + "version": "4.0.1", + "bundled": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "yallist": { + "version": "4.0.0", + "bundled": true + } + } + }, "npm-bundled": { "version": "1.1.2", "resolved": "https://registry.npmmirror.com/npm-bundled/-/npm-bundled-1.1.2.tgz", diff --git a/maxkey-web-frontend/maxkey-web-app/package.json b/maxkey-web-frontend/maxkey-web-app/package.json index 43df846bc..d7025edf9 100644 --- a/maxkey-web-frontend/maxkey-web-app/package.json +++ b/maxkey-web-frontend/maxkey-web-app/package.json @@ -66,6 +66,7 @@ "ngx-cookie-service": "^13.2.0", "ngx-tinymce": "^13.0.0", "ngx-ueditor": "^13.0.0", + "npm": "^8.5.5", "rxjs": "~7.5.0", "screenfull": "^6.0.1", "tslib": "^2.3.0", diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/entity/JobConfigFeild.ts b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/entity/JobConfigFeild.ts new file mode 100644 index 000000000..97759ad63 --- /dev/null +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/entity/JobConfigFeild.ts @@ -0,0 +1,46 @@ + +/* + * Copyright [2022] [MaxKey of copyright http://www.maxkey.top] + * + * 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. + */ + + +import { BaseEntity } from './BaseEntity'; + +export class JobConfigFeild extends BaseEntity { + jobId!: String; + name!: String; + objectType!: String; + targetField!: String; + sourceField!: String; + + constructor() { + super(); + } + + override init(data: any): void { + Object.assign(this, data); + if (this.status == 1) { + this.switch_status = true; + } + + } + override trans(): void { + if (this.switch_status) { + this.status = 1; + } else { + this.status = 0; + } + } +} diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/config.module.ts b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/config.module.ts index 6d65d37b4..fa2aacee2 100644 --- a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/config.module.ts +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/config.module.ts @@ -45,6 +45,10 @@ import { SocialsProviderEditerComponent } from './socials-provider/socials-provi import { SocialsProviderComponent } from './socials-provider/socials-provider.component'; import { SynchronizerEditerComponent } from './synchronizers/synchronizer-editer/synchronizer-editer.component'; import { SynchronizersComponent } from './synchronizers/synchronizers.component'; +import { SynchronizerConfigFieldComponent } from './synchronizers/synchronizer-config-field/synchronizer-config-field.component'; +import { + SynchronizerConfigFieldEditComponent +} from "./synchronizers/synchronizer-config-field/editer/synchronizer-config-field-edit.component"; const routes: Routes = [ { @@ -115,7 +119,9 @@ const COMPONENTS = [PasswordPolicyComponent, EmailSendersComponent, LdapContextC SelectAccountsStrategyComponent, SelectAdaptersComponent, ConnectorsComponent, - ConnectorEditerComponent + ConnectorEditerComponent, + SynchronizerConfigFieldComponent, + SynchronizerConfigFieldEditComponent ], imports: [SharedModule, CommonModule, RouterModule.forChild(routes)], exports: [RouterModule] diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/editer/synchronizer-config-field-edit.component.html b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/editer/synchronizer-config-field-edit.component.html new file mode 100644 index 000000000..95699f6ef --- /dev/null +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/editer/synchronizer-config-field-edit.component.html @@ -0,0 +1,41 @@ +
{{ isEdit ? ('mxk.text.edit' | i18n) : ('mxk.text.add' | i18n) }}
+
+
+ + {{ 'mxk.job.mapping.sourceField' | i18n }} + + + + + + + {{ 'mxk.job.mapping.targetField' | i18n }} + + + + + + {{ 'mxk.job.mapping.description' | i18n }} + + + + + + {{ 'mxk.job.mapping.objectType' | i18n }} + + + + + + + +
+
+ +
+ + +
diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/editer/synchronizer-config-field-edit.component.ts b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/editer/synchronizer-config-field-edit.component.ts new file mode 100644 index 000000000..cea6c76e0 --- /dev/null +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/editer/synchronizer-config-field-edit.component.ts @@ -0,0 +1,92 @@ +/* + * Copyright [2022] [MaxKey of copyright http://www.maxkey.top] + * + * 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. + */ + +import { Component, ChangeDetectorRef, Input, OnInit, Inject } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { I18NService } from '@core'; +import { _HttpClient, ALAIN_I18N_TOKEN, SettingsService } from '@delon/theme'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { NzModalRef } from 'ng-zorro-antd/modal'; + +import { JobConfigFeild } from '../../../../../entity/JobConfigFeild'; +import { SynchronizersService } from '../../../../../service/synchronizers.service'; + + +@Component({ + selector: 'app-synchronizer-config-field-edit', + templateUrl: './synchronizer-config-field-edit.component.html', + styles: [ + ` + nz-form-item { + width: 100%; + } + ` + ], +}) +export class SynchronizerConfigFieldEditComponent implements OnInit { + @Input() id?: String; + @Input() jobId?: String; + @Input() isEdit?: boolean; + + form: { + submitting: boolean; + model: JobConfigFeild + } = { + submitting: false, + model: new JobConfigFeild(), + }; + formGroup: FormGroup = new FormGroup({}); + constructor( + private modalRef: NzModalRef, + private synchronizersService: SynchronizersService, + private fb: FormBuilder, + private msg: NzMessageService, + @Inject(ALAIN_I18N_TOKEN) private i18n: I18NService, + private cdr: ChangeDetectorRef + ) {} + + ngOnInit(): void { + this.get() + } + get(){ + if (this.isEdit) { + this.synchronizersService.getField(`${this.id}`).subscribe(res => { + this.form.model.init(res.data); + this.cdr.detectChanges(); + }); + } + } + onClose(e: MouseEvent): void { + e.preventDefault(); + this.modalRef.destroy({ refresh: false }); + } + + onSubmit(e: MouseEvent): void { + e.preventDefault(); + this.form.submitting = true; + this.form.model.jobId = this.jobId +""; + (this.isEdit ? this.synchronizersService.mappingUpdate(this.form.model) : this.synchronizersService.mappingAdd(this.form.model)).subscribe(res => { + if (res.code == 0) { + this.msg.success(this.i18n.fanyi(this.isEdit ? 'mxk.alert.update.success' : 'mxk.alert.add.success')); + } else { + this.msg.error(this.i18n.fanyi(this.isEdit ? 'mxk.alert.update.error' : 'mxk.alert.add.error')); + } + this.form.submitting = false; + this.modalRef.destroy({ refresh: true }); + this.cdr.detectChanges(); + }); + } +} diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/synchronizer-config-field.component.html b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/synchronizer-config-field.component.html new file mode 100644 index 000000000..d01261b48 --- /dev/null +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/synchronizer-config-field.component.html @@ -0,0 +1,41 @@ +
{{ ('mxk.text.mapping' | i18n) }}
+
+ +
+
+ +
+
+ + + + {{ 'mxk.job.mapping.sourceField' | i18n }} + {{ 'mxk.job.mapping.targetField' | i18n }} + {{ 'mxk.job.mapping.description' | i18n }} + {{ 'mxk.job.mapping.objectType' | i18n }} + {{ 'mxk.text.action' | i18n }} + + + + + {{ data.sourceField }} + {{ data.targetField }} + {{ data.description }} + + {{ data.objectType == '1' ? ('mxk.menu.identities.users' | i18n) : ('mxk.menu.identities.organizations' | i18n) }} + + + + + + + + +
+
+
+ +
+ + +
diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/synchronizer-config-field.component.less b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/synchronizer-config-field.component.less new file mode 100644 index 000000000..e69de29bb diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/synchronizer-config-field.component.spec.ts b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/synchronizer-config-field.component.spec.ts new file mode 100644 index 000000000..272e92912 --- /dev/null +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/synchronizer-config-field.component.spec.ts @@ -0,0 +1,42 @@ +/* + * Copyright [2022] [MaxKey of copyright http://www.maxkey.top] + * + * 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. + */ + + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SynchronizerConfigFieldComponent } from './synchronizer-config-field.component'; + +describe('SynchronizerConfigFieldComponent', () => { + let component: SynchronizerConfigFieldComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SynchronizerConfigFieldComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SynchronizerConfigFieldComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/synchronizer-config-field.component.ts b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/synchronizer-config-field.component.ts new file mode 100644 index 000000000..16694ee70 --- /dev/null +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizer-config-field/synchronizer-config-field.component.ts @@ -0,0 +1,148 @@ +/* + * Copyright [2022] [MaxKey of copyright http://www.maxkey.top] + * + * 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. + */ + +import {Component, ChangeDetectorRef, Input, OnInit, Inject, ViewContainerRef} from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { I18NService } from '@core'; +import { _HttpClient, ALAIN_I18N_TOKEN, SettingsService } from '@delon/theme'; +import format from 'date-fns/format'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal'; + +import { JobConfigFeild } from '../../../../entity/JobConfigFeild'; +import { SynchronizersService } from '../../../../service/synchronizers.service'; +import {NzSafeAny} from "ng-zorro-antd/core/types"; +import { SynchronizerConfigFieldEditComponent } from './editer/synchronizer-config-field-edit.component'; + +@Component({ + selector: 'app-synchronizer-config-field', + templateUrl: './synchronizer-config-field.component.html', + styles: [ + ` + nz-form-item { + width: 100%; + } + ` + ], + styleUrls: ['./synchronizer-config-field.component.less'] +}) +export class SynchronizerConfigFieldComponent implements OnInit { + @Input() jobId?: String; + @Input() isEdit?: boolean; + + form: { + submitting: boolean; + rows: NzSafeAny[] + } = { + submitting: false, + rows: [] + }; + + formGroup: FormGroup = new FormGroup({}); + + constructor( + private modalRef: NzModalRef, + private modalService: NzModalService, + private synchronizersService: SynchronizersService, + private viewContainerRef: ViewContainerRef, + private fb: FormBuilder, + private msg: NzMessageService, + @Inject(ALAIN_I18N_TOKEN) private i18n: I18NService, + private cdr: ChangeDetectorRef + ) {} + + ngOnInit(): void { + this.fetch() + } + fetch(){ + this.synchronizersService.getMapping(`${this.jobId}`).subscribe(res => { + this.form.rows = res.data + this.cdr.detectChanges(); + }); + } + onClose(e: MouseEvent): void { + e.preventDefault(); + this.modalRef.destroy({ refresh: false }); + } + + onDelete(e: MouseEvent, deleteId: String): void { + e.preventDefault(); + this.synchronizersService.deleteMapping(deleteId).subscribe(res => { + if (res.code == 0) { + this.msg.success(this.i18n.fanyi('mxk.alert.delete.success')); + this.fetch(); + } else { + this.msg.error(this.i18n.fanyi('mxk.alert.delete.error')); + } + this.cdr.detectChanges(); + }); + } + onEdit(e: MouseEvent, id: String): void { + e.preventDefault(); + const modal = this.modalService.create({ + nzContent: SynchronizerConfigFieldEditComponent, + nzViewContainerRef: this.viewContainerRef, + nzComponentParams: { + isEdit: true, + id: id, + jobId: this.jobId, + }, + nzWidth: 1200, + nzOnOk: () => new Promise(resolve => setTimeout(resolve, 1000)) + }); + // Return a result when closed + modal.afterClose.subscribe(result => { + if (result.refresh) { + this.fetch(); + } + }); + } + onAdd(e: MouseEvent): void { + e.preventDefault(); + const modal = this.modalService.create({ + nzContent: SynchronizerConfigFieldEditComponent, + nzViewContainerRef: this.viewContainerRef, + nzComponentParams: { + isEdit: false, + jobId: this.jobId, + }, + nzWidth: 1200, + nzOnOk: () => new Promise(resolve => setTimeout(resolve, 1000)) + }); + // Return a result when closed + modal.afterClose.subscribe(result => { + if (result.refresh) { + this.fetch(); + } + }); + } + + onSubmit(e: MouseEvent): void { + e.preventDefault(); + this.form.submitting = true; + + /* (this.isEdit ? this.synchronizersService.update(this.form.model) : this.synchronizersService.add(this.form.model)).subscribe(res => { + if (res.code == 0) { + this.msg.success(this.i18n.fanyi(this.isEdit ? 'mxk.alert.update.success' : 'mxk.alert.add.success')); + } else { + this.msg.error(this.i18n.fanyi(this.isEdit ? 'mxk.alert.update.error' : 'mxk.alert.add.error')); + } + this.form.submitting = false; + this.modalRef.destroy({ refresh: true }); + this.cdr.detectChanges(); + });*/ + } +} diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizers.component.html b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizers.component.html index 6b5dcb8bc..d5ff1bcd4 100644 --- a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizers.component.html +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizers.component.html @@ -40,12 +40,12 @@ - Id - {{ 'mxk.synchronizers.name' | i18n }} - {{ 'mxk.synchronizers.scheduler' | i18n }} - {{ 'mxk.text.status' | i18n }} - {{ 'mxk.text.action' | i18n }} - + Id + {{ 'mxk.synchronizers.name' | i18n }} + {{ 'mxk.synchronizers.scheduler' | i18n }} + {{ 'mxk.text.status' | i18n }} + {{ 'mxk.text.action' | i18n }} + @@ -55,22 +55,25 @@ {{ data.id }} - {{ data.name }} - {{ data.scheduler }} - - -
- - - -
- - + {{ data.name }} + {{ data.scheduler }} + + +
+ + + + + + +
+ + - \ No newline at end of file + diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizers.component.ts b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizers.component.ts index f775b6f64..08011d81a 100644 --- a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizers.component.ts +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/config/synchronizers/synchronizers.component.ts @@ -27,6 +27,7 @@ import { NzTableQueryParams } from 'ng-zorro-antd/table'; import { SynchronizersService } from '../../../service/synchronizers.service'; import { set2String } from '../../../shared/index'; import { SynchronizerEditerComponent } from './synchronizer-editer/synchronizer-editer.component'; +import { SynchronizerConfigFieldComponent } from './synchronizer-config-field/synchronizer-config-field.component'; @Component({ selector: 'app-synchronizers', templateUrl: './synchronizers.component.html', @@ -149,6 +150,7 @@ export class SynchronizersComponent implements OnInit { }); } + onEdit(e: MouseEvent, editId: String): void { e.preventDefault(); const modal = this.modalService.create({ @@ -158,6 +160,26 @@ export class SynchronizersComponent implements OnInit { isEdit: true, id: editId }, + + nzOnOk: () => new Promise(resolve => setTimeout(resolve, 1000)) + }); + // Return a result when closed + modal.afterClose.subscribe(result => { + if (result.refresh) { + this.fetch(); + } + }); + } + onConfigFeild(e: MouseEvent, jobId: String): void { + e.preventDefault(); + const modal = this.modalService.create({ + nzContent: SynchronizerConfigFieldComponent, + nzViewContainerRef: this.viewContainerRef, + nzComponentParams: { + isEdit: true, + jobId: jobId + }, + nzWidth: 1200, nzOnOk: () => new Promise(resolve => setTimeout(resolve, 1000)) }); // Return a result when closed @@ -168,7 +190,8 @@ export class SynchronizersComponent implements OnInit { }); } - onDelete(deleteId: String): void { + + onDelete( deleteId: String): void { this.synchronizersService.delete(deleteId).subscribe(res => { if (res.code == 0) { this.msg.success(this.i18n.fanyi('mxk.alert.delete.success')); diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/service/synchronizers.service.ts b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/service/synchronizers.service.ts index b66a5c35d..69664eba0 100644 --- a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/service/synchronizers.service.ts +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/service/synchronizers.service.ts @@ -22,6 +22,7 @@ import { Observable } from 'rxjs'; import { Message } from '../entity/Message'; import { Synchronizers } from '../entity/Synchronizers'; import { BaseService } from './base.service'; +import {JobConfigFeild} from "../entity/JobConfigFeild"; @Injectable({ providedIn: 'root' @@ -34,4 +35,24 @@ export class SynchronizersService extends BaseService { synchr(synchrId: String): Observable> { return this.http.get>(`${`${this.server.urls.base}/synchr`}?id=${synchrId}`); } + getMapping(synchrId: String): Observable> { + return this.http.get>(`${`${this.server.urls.base}/mapping-list`}/${synchrId}`); + } + + getField(id: String): Observable> { + return this.http.get>(`${`${this.server.urls.base}/mapping-get`}/${id}`); + } + + mappingAdd(body: any): Observable> { + return this.http.post>(`${this.server.urls.base}/mapping-add`, body); + } + + mappingUpdate(body: any): Observable> { + return this.http.put>(`${this.server.urls.base}/mapping-update`, body); + } + + deleteMapping(id: String): Observable> { + return this.http.get>(`${`${this.server.urls.base}/mapping-delete`}/${id}`); + } + } diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/theme/layout-default/style/_layout.less b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/theme/layout-default/style/_layout.less index 6e9597376..23e0922e5 100644 --- a/maxkey-web-frontend/maxkey-web-mgt-app/src/app/theme/layout-default/style/_layout.less +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/app/theme/layout-default/style/_layout.less @@ -119,6 +119,10 @@ body { margin-bottom: 2px !important; } +.table_cell_action_5 { + width: 360px; +} + .table_cell_action_3 { width: 240px; } diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/en-US.json b/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/en-US.json index 2dfe73f88..b0c5b665a 100644 --- a/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/en-US.json +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/en-US.json @@ -943,5 +943,10 @@ "validation.title.required": "Please enter a title", "validation.date.required": "Please select the start and end date", "validation.goal.required": "Please enter a description of the goal", - "validation.standard.required": "Please enter a metric" + "validation.standard.required": "Please enter a metric", + "mxk.text.mapping": "Feild Mapping", + "mxk.job.mapping.targetField": "TargetField", + "mxk.job.mapping.sourceField": "SourceField", + "mxk.job.mapping.objectType": "ObjectType", + "mxk.job.mapping.description": "Description" } diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-CN.json b/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-CN.json index 8b9650eee..f7037d381 100644 --- a/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-CN.json +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-CN.json @@ -935,5 +935,12 @@ "validation.title.required": "请输入标题", "validation.date.required": "请选择起止日期", "validation.goal.required": "请输入目标描述", - "validation.standard.required": "请输入衡量标准" + "validation.standard.required": "请输入衡量标准", + "mxk.text.mapping": "属性映射", + "mxk.job.mapping.targetField": "目标字段", + "mxk.job.mapping.sourceField": "来源字段", + "mxk.job.mapping.objectType": "映射类型", + "mxk.job.mapping.description": "规则说明" + + } diff --git a/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-TW.json b/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-TW.json index cb29d3077..98cef7216 100644 --- a/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-TW.json +++ b/maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-TW.json @@ -936,5 +936,10 @@ "validation.title.required": "請輸入標題", "validation.date.required": "請選擇起止日期", "validation.goal.required": "請輸入目標描述", - "validation.standard.required": "請輸入衡量標準" + "validation.standard.required": "請輸入衡量標準", + "mxk.text.mapping": "属性映射", + "mxk.job.mapping.targetField": "目标字段", + "mxk.job.mapping.sourceField": "来源字段", + "mxk.job.mapping.objectType": "映射类型", + "mxk.job.mapping.description": "规则说明" } diff --git a/maxkey-webs/maxkey-web-maxkey/src/main/resources/application-maxkey.properties b/maxkey-webs/maxkey-web-maxkey/src/main/resources/application-maxkey.properties index 4145e1693..618087634 100644 --- a/maxkey-webs/maxkey-web-maxkey/src/main/resources/application-maxkey.properties +++ b/maxkey-webs/maxkey-web-maxkey/src/main/resources/application-maxkey.properties @@ -103,9 +103,9 @@ maxkey.notices.visible =false spring.datasource.type =com.alibaba.druid.pool.DruidDataSource #mysql spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver -spring.datasource.username =${DATABASE_USER:root} -spring.datasource.password =${DATABASE_PWD:maxkey} -spring.datasource.url =jdbc:mysql://${DATABASE_HOST:localhost}:${DATABASE_PORT:3306}/${DATABASE_NAME:maxkey}?autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC +spring.datasource.username =root +spring.datasource.password =root +spring.datasource.url =jdbc:mysql://127.0.0.1:3306/maxkey?useSSL=false&serverTimezone=UTC #highgo #spring.datasource.driver-class-name=com.highgo.jdbc.Driver #spring.datasource.username=highgo diff --git a/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyMgtConfig.java b/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyMgtConfig.java index 1af0938ca..b5a7761b1 100644 --- a/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyMgtConfig.java +++ b/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyMgtConfig.java @@ -25,6 +25,8 @@ import org.dromara.maxkey.persistence.repository.LoginHistoryRepository; import org.dromara.maxkey.persistence.repository.LoginRepository; import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; import org.dromara.maxkey.persistence.service.UserInfoService; +import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.synchronizer.ldap.LdapSynchronizerService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; @@ -69,4 +71,12 @@ public class MaxKeyMgtConfig { return tfaOtpAuthn; } + /*@Bean + public ISynchronizerService ldapSynchronizerService() { + LdapSynchronizerService ldapSynchronizerService = new LdapSynchronizerService(); + ldapSynchronizerService.setId("LDAP_11122"); + ldapSynchronizerService.syncOrg(); + return ldapSynchronizerService; + }*/ + } diff --git a/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/web/config/contorller/SynchronizersController.java b/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/web/config/contorller/SynchronizersController.java index 6e528ac23..be19210d8 100644 --- a/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/web/config/contorller/SynchronizersController.java +++ b/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/web/config/contorller/SynchronizersController.java @@ -20,6 +20,10 @@ package org.dromara.maxkey.web.config.contorller; import org.apache.commons.lang3.StringUtils; import org.dromara.maxkey.authn.annotation.CurrentUser; import org.dromara.maxkey.crypto.password.PasswordReciprocal; +import org.dromara.maxkey.entity.*; +import org.dromara.maxkey.persistence.service.SynchronizersService; +import org.dromara.maxkey.synchronizer.ISynchronizerService; +import org.dromara.maxkey.synchronizer.service.SyncJobConfigFieldService; import org.dromara.maxkey.entity.Connectors; import org.dromara.maxkey.entity.Message; import org.dromara.maxkey.entity.Synchronizers; @@ -30,10 +34,13 @@ import org.dromara.maxkey.util.StrUtils; import org.dromara.maxkey.web.WebContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.Date; import java.util.List; @RestController @@ -44,6 +51,9 @@ public class SynchronizersController { @Autowired SynchronizersService synchronizersService; + @Autowired + SyncJobConfigFieldService syncJobConfigFieldService; + @RequestMapping(value = {"/fetch"}, produces = {MediaType.APPLICATION_JSON_VALUE}) @ResponseBody public Message fetch(Synchronizers synchronizers, @CurrentUser UserInfo currentUser) { @@ -126,4 +136,53 @@ public class SynchronizersController { return new Message(Message.SUCCESS); } + + @RequestMapping(value = {"/mapping-list/{jobId}"}, produces = {MediaType.APPLICATION_JSON_VALUE}) + @ResponseBody + public ResponseEntity mapping(@PathVariable Long jobId) { + logger.debug("mapping {}", jobId); + List syncJobConfigFields = syncJobConfigFieldService.findByJobId(jobId); + return new Message<>(syncJobConfigFields).buildResponse(); + } + + @RequestMapping(value = {"/mapping-get/{id}"}, produces = {MediaType.APPLICATION_JSON_VALUE}) + @ResponseBody + public ResponseEntity mappingGet(@PathVariable Long id) { + logger.debug("mapping get {}", id); + SyncJobConfigField syncJobConfigFields = syncJobConfigFieldService.get(String.valueOf(id)); + return new Message<>(syncJobConfigFields).buildResponse(); + } + + @RequestMapping(value = {"/mapping-delete/{id}"}, produces = {MediaType.APPLICATION_JSON_VALUE}) + @ResponseBody + public ResponseEntity mappingDelete(@PathVariable Long id) { + logger.debug("mappingDelete {}", id); + syncJobConfigFieldService.deleteFieldMapById(id); + return new Message(Message.SUCCESS).buildResponse(); + } + + @ResponseBody + @PostMapping(value = {"/mapping-add"}, produces = {MediaType.APPLICATION_JSON_VALUE}) + public ResponseEntity mappingadd(@RequestBody SyncJobConfigField syncJobConfigField, @CurrentUser UserInfo currentUser) { + logger.debug("-mapping add : {}", syncJobConfigField); + syncJobConfigField.setCreateTime(new Date()); + if (syncJobConfigFieldService.insert(syncJobConfigField)) { + return new Message(Message.SUCCESS).buildResponse(); + } else { + return new Message(Message.FAIL).buildResponse(); + } + } + + @ResponseBody + @PutMapping(value = {"/mapping-update"}, produces = {MediaType.APPLICATION_JSON_VALUE}) + public ResponseEntity mappingupdate(@RequestBody SyncJobConfigField syncJobConfigField, @CurrentUser UserInfo currentUser) { + logger.debug("-mapping update : {}", syncJobConfigField); + syncJobConfigField.setUpdateTime(new Date()); + if (syncJobConfigFieldService.update(syncJobConfigField)) { + return new Message(Message.SUCCESS).buildResponse(); + } else { + return new Message(Message.FAIL).buildResponse(); + } + } + } diff --git a/maxkey-webs/maxkey-web-mgt/src/main/resources/application-maxkey-mgt.properties b/maxkey-webs/maxkey-web-mgt/src/main/resources/application-maxkey-mgt.properties index 351fc7d68..f967c3ae5 100644 --- a/maxkey-webs/maxkey-web-mgt/src/main/resources/application-maxkey-mgt.properties +++ b/maxkey-webs/maxkey-web-mgt/src/main/resources/application-maxkey-mgt.properties @@ -76,9 +76,9 @@ maxkey.login.jwt.issuer =${LOGIN_JWT_ISSUER:${maxkey.ser spring.datasource.type =com.alibaba.druid.pool.DruidDataSource #mysql spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver -spring.datasource.username =${DATABASE_USER:root} -spring.datasource.password =${DATABASE_PWD:maxkey} -spring.datasource.url =jdbc:mysql://${DATABASE_HOST:localhost}:${DATABASE_PORT:3306}/${DATABASE_NAME:maxkey}?autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC +spring.datasource.username =root +spring.datasource.password =root +spring.datasource.url =jdbc:mysql://localhost/maxkey?autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false #highgo #spring.datasource.driver-class-name=com.highgo.jdbc.Driver #spring.datasource.username=highgo diff --git a/summer-ospp/2024/SyncMapper/sync_job_config_field.sql b/summer-ospp/2024/SyncMapper/sync_job_config_field.sql new file mode 100644 index 000000000..3b77d0825 --- /dev/null +++ b/summer-ospp/2024/SyncMapper/sync_job_config_field.sql @@ -0,0 +1,255 @@ +/* + Navicat Premium Data Transfer + + Source Server : mysql80 + Source Server Type : MySQL + Source Server Version : 80038 + Source Host : localhost:3306 + Source Schema : maxkey + + Target Server Type : MySQL + Target Server Version : 80038 + File Encoding : 65001 + + Date: 26/09/2024 10:36:51 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for sync_job_config_field +-- ---------------------------- +DROP TABLE IF EXISTS `sync_job_config_field`; +CREATE TABLE `sync_job_config_field` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + `jobid` bigint NOT NULL DEFAULT 0 COMMENT '同步任务ID', + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '规则名', + `objecttype` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '类型', + `targetfield` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '目标字段', + `targetfieldname` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '目标字段描述', + `sourcefield` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '来源字段', + `sourcefieldname` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '来源字段描述', + `description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '描述', + `createuser` bigint NULL DEFAULT 0 COMMENT '创建人', + `createtime` datetime NULL DEFAULT NULL COMMENT '创建时间', + `updateuser` bigint NULL DEFAULT 0 COMMENT '修改人', + `updatetime` datetime NULL DEFAULT NULL COMMENT '修改时间', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_job_id`(`jobid` ASC) USING BTREE COMMENT '同步任务ID索引' +) ENGINE = InnoDB AUTO_INCREMENT = 214 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '同步任务字段映射表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sync_job_config_field +-- ---------------------------- +INSERT INTO `sync_job_config_field` VALUES (1, 3, NULL, '1', 'username', NULL, 'userid', NULL, '钉钉用户', NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (2, 3, NULL, '1', 'nickName', NULL, 'name', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (3, 3, NULL, '1', 'displayName', NULL, 'name', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (4, 3, NULL, '1', 'formattedName', NULL, 'name', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (5, 3, NULL, '1', 'email', NULL, 'email', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (6, 3, NULL, '1', 'entryDate', NULL, 'hiredDate', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (7, 3, NULL, '1', 'mobile', NULL, 'mobile', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (8, 3, NULL, '1', 'departmentId', NULL, 'objectId', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (9, 3, NULL, '1', 'department', NULL, 'objectName', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (10, 3, NULL, '1', 'employeeNumber', NULL, 'jobNumber', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (11, 3, NULL, '1', 'jobTitle', NULL, 'title', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (12, 3, NULL, '1', 'workEmail', NULL, 'orgEmail', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (13, 3, NULL, '1', 'workPhoneNumber', NULL, 'telephone', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (14, 3, NULL, '1', 'workOfficeName', NULL, 'workPlace', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (15, 3, NULL, '1', 'status', NULL, 'active', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (16, 3, '', '1', 'description', '', 'remark', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (17, 3, NULL, '2', 'id', NULL, 'deptId', NULL, '钉钉组织', NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (18, 3, NULL, '2', 'orgCode', NULL, 'deptId', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (19, 3, NULL, '2', 'orgName', NULL, 'name', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (20, 3, NULL, '2', 'parentId', NULL, 'objectId', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (21, 3, NULL, '2', 'parentCode', NULL, 'parentId', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (22, 3, NULL, '2', 'parentName', NULL, 'objectName', NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sync_job_config_field` VALUES (23, 6, '', '1', 'username', '', 'user_id', '', '飞书用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (24, 6, '', '1', 'nickName', '', 'nickname', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (25, 6, '', '1', 'displayName', '', 'name', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (26, 6, '', '1', 'mobile', '', 'mobile', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (27, 6, '', '1', 'email', '', 'email', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (28, 6, '', '1', 'gender', '', 'gender', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (29, 6, '', '1', 'employeeNumber', '', 'employee_no', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (30, 6, '', '1', 'workPhoneNumber', '', 'mobile', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (31, 6, '', '1', 'department', '', 'objectName', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (32, 6, '', '1', 'jobTitle', '', 'job_title', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (33, 6, '', '1', 'workAddressFormatted', '', 'work_station', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (34, 6, '', '1', 'status', '', 'status', '', '', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (35, 6, '', '2', 'orgCode', '', 'department_id', '', '飞书组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (36, 6, '', '2', 'orgName', '', 'name', '', '飞书组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (37, 6, '', '2', 'fullName', '', 'name', '', '飞书组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (38, 6, '', '2', 'parentId', '', 'objectId', '', '飞书组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (39, 6, '', '2', 'parentName', '', 'objectName', '', '飞书组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (40, 6, '', '2', 'sortIndex', '', 'order', '', '飞书组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (41, 4, '', '1', 'username', '', 'userid', '', '企业微信用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (42, 4, '', '1', 'nickName', '', 'alias', '', '企业微信用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (43, 4, '', '1', 'displayName', '', 'name', '', '企业微信用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (44, 4, '', '1', 'mobile', '', 'mobile', '', '企业微信用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (45, 4, '', '1', 'email', '', 'email', '', '企业微信用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (46, 4, '', '1', 'gender', '', 'gender', '', '企业微信用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (47, 4, '', '1', 'workPhoneNumber', '', 'telephone', '', '企业微信用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (48, 4, '', '1', 'departmentId', '', 'main_department', '', '企业微信用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (49, 4, '', '1', 'jobTitle', '', 'position', '', '企业微信用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (50, 4, '', '1', 'workAddressFormatted', '', 'address', '', '企业微信用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (51, 4, '', '2', 'orgName', '', 'name', '', '企业微信组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (52, 4, '', '2', 'orgCode', '', 'id', '', '企业微信组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (53, 4, '', '2', 'parentId', '', 'objectId', '', '企业微信组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (54, 4, '', '2', 'parentName', '', 'objectName', '', '企业微信组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (55, 4, '', '2', 'sortIndex', '', 'order', '', '企业微信组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (56, 2, '', '1', 'department', '', 'orgName', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (57, 2, '', '1', 'departmentId', '', 'id', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (58, 2, '', '1', 'formattedName', '', 'cn', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (59, 2, '', '1', 'username', '', 'sAMAccountname', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (60, 2, '', '1', 'windowsAccount', '', 'sAMAccountname', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (61, 2, '', '1', 'familyName', '', 'sn', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (62, 2, '', '1', 'givenName', '', 'givenName', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (63, 2, '', '1', 'nameZhShortSpell', '', 'initials', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (64, 2, '', '1', 'nickName', '', 'initials', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (65, 2, '', '1', 'displayName', '', 'displayName', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (66, 2, '', '1', 'description', '', 'description', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (67, 2, '', '1', 'workPhoneNumber', '', 'telephoneNumber', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (68, 2, '', '1', 'workOfficeName', '', 'physicalDeliveryOfficeName', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (69, 2, '', '1', 'workEmail', '', 'mail', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (70, 2, '', '1', 'webSite', '', 'wwwHomePage', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (71, 2, '', '1', 'workCountry', '', 'co', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (72, 2, '', '1', 'workRegion', '', 'st', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (73, 2, '', '1', 'workLocality', '', 'l', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (74, 2, '', '1', 'workStreetAddress', '', 'streetAddress', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (75, 2, '', '1', 'workPostalCode', '', 'postalCode', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (76, 2, '', '1', 'workAddressFormatted', '', 'postOfficeBox', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (77, 2, '', '1', 'mobile', '', 'mobile', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (78, 2, '', '1', 'homePhoneNumber', '', 'homePhone', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (79, 2, '', '1', 'workFax', '', 'facsimileTelephoneNumber', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (80, 2, '', '1', 'homeAddressFormatted', '', 'info', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (81, 2, '', '1', 'division', '', 'company', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (82, 2, '', '1', 'jobTitle', '', 'title', '', 'AD用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (83, 2, '', '2', 'orgCode', '', 'id', '', 'AD组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (84, 2, '', '2', 'orgName', '', 'ou', '', 'AD组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (85, 2, '', '2', 'fullName', '', 'orgName', '', 'AD组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (86, 2, '', '2', 'country', '', 'co', '', 'AD组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (87, 2, '', '2', 'region', '', 'st', '', 'AD组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (88, 2, '', '2', 'locality', '', 'l', '', 'AD组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (89, 2, '', '2', 'street', '', 'street', '', 'AD组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (90, 2, '', '2', 'postalCode', '', 'postalCode', '', 'AD组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (91, 2, '', '2', 'description', '', 'description', '', 'AD组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (92, 1, '', '1', 'department', '', 'orgName', '', 'LDAP用户', 0, NULL, 0, '2024-09-24 04:06:12'); +INSERT INTO `sync_job_config_field` VALUES (93, 1, '', '1', 'departmentId', '', 'id', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (94, 1, '', '1', 'formattedName', '', 'givenName', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (95, 1, '', '1', 'username', '', 'uid', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (96, 1, '', '1', 'windowsAccount', '', 'uid', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (97, 1, '', '1', 'familyName', '', 'sn', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (98, 1, '', '1', 'givenName', '', 'givenName', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (99, 1, '', '1', 'nickName', '', 'initials', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (100, 1, '', '1', 'nameZhShortSpell', '', 'initials', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (101, 1, '', '1', 'displayName', '', 'displayName', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (102, 1, '', '1', 'employeeNumber', '', 'employeeNumber', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (103, 1, '', '1', 'jobTitle', '', 'title', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (104, 1, '', '1', 'workOfficeName', '', 'physicalDeliveryOfficeName', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (105, 1, '', '1', 'workEmail', '', 'mail', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (106, 1, '', '1', 'workRegion', '', 'st', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (107, 1, '', '1', 'workLocality', '', 'l', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (108, 1, '', '1', 'workStreetAddress', '', 'street', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (109, 1, '', '1', 'workPostalCode', '', 'postalCode', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (110, 1, '', '1', 'workAddressFormatted', '', 'postOfficeBox', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (111, 1, '', '1', 'workFax', '', 'facsimileTelephoneNumber', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (112, 1, '', '1', 'homePhoneNumber', '', 'homePhone', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (113, 1, '', '1', 'homeAddressFormatted', '', 'homePostalAddress', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (114, 1, '', '1', 'mobile', '', 'mobile', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (115, 1, '', '1', 'preferredLanguage', '', 'preferredLanguage', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (116, 1, '', '1', 'description', '', 'description', '', 'LDAP用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (117, 1, '', '2', 'orgCode', '', 'id', '', 'LDAP组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (118, 1, '', '2', 'orgName', '', 'ou', '', 'LDAP组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (119, 1, '', '2', 'fullName', '', 'orgName', '', 'LDAP组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (120, 1, '', '2', 'region', '', 'st', '', 'LDAP组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (121, 1, '', '2', 'locality', '', 'l', '', 'LDAP组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (122, 1, '', '2', 'street', '', 'street', '', 'LDAP组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (123, 1, '', '2', 'postalCode', '', 'postalCode', '', 'LDAP组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (124, 1, '', '2', 'address', '', 'postalAddress', '', 'LDAP组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (125, 1, '', '2', 'phone', '', 'telephoneNumber', '', 'LDAP组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (126, 1, '', '2', 'fax', '', 'facsimileTelephoneNumber', '', 'LDAP组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (127, 1, '', '2', 'description', '', 'description', '', 'LDAP组织', 0, NULL, 0, '2024-09-24 04:12:57'); +INSERT INTO `sync_job_config_field` VALUES (128, 7, '', '1', 'id', '', 'id', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (129, 7, '', '1', 'username', '', 'username', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (130, 7, '', '1', 'picture', '', 'picture', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (131, 7, '', '1', 'displayName', '', 'displayname', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (132, 7, '', '1', 'nickName', '', 'nickname', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (133, 7, '', '1', 'mobile', '', 'mobile', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (134, 7, '', '1', 'email', '', 'email', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (135, 7, '', '1', 'birthDate', '', 'birthdate', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (136, 7, '', '1', 'userType', '', 'usertype', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (137, 7, '', '1', 'userState', '', 'userstate', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (138, 7, '', '1', 'windowsAccount', '', 'windowsaccount', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (139, 7, '', '1', 'givenName', '', 'givenname', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (140, 7, '', '1', 'middleName', '', 'middlename', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (141, 7, '', '1', 'married', '', 'married', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (142, 7, '', '1', 'gender', '', 'gender', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (143, 7, '', '1', 'idType', '', 'idtype', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (144, 7, '', '1', 'idCardNo', '', 'idcardno', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (145, 7, '', '1', 'webSite', '', 'website', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (146, 7, '', '1', 'startWorkDate', '', 'startworkdate', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (147, 7, '', '1', 'workCountry', '', 'workcountry', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (148, 7, '', '1', 'workRegion', '', 'workregion', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (149, 7, '', '1', 'workLocality', '', 'worklocality', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (150, 7, '', '1', 'workStreetAddress', '', 'workstreetaddress', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (151, 7, '', '1', 'workAddressFormatted', '', 'workaddressformatted', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (152, 7, '', '1', 'workEmail', '', 'workemail', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (153, 7, '', '1', 'workPhoneNumber', '', 'workphonenumber', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (154, 7, '', '1', 'workPostalCode', '', 'workpostalcode', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (155, 7, '', '1', 'workFax', '', 'workfax', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (156, 7, '', '1', 'workOfficeName', '', 'workofficename', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (157, 7, '', '1', 'homeCountry', '', 'homecountry', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (158, 7, '', '1', 'homeRegion', '', 'homeregion', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (159, 7, '', '1', 'homeLocality', '', 'homelocality', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (160, 7, '', '1', 'homeStreetAddress', '', 'homestreetaddress', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (161, 7, '', '1', 'homeAddressFormatted', '', 'homeaddressformatted', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (162, 7, '', '1', 'homeEmail', '', 'homeemail', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (163, 7, '', '1', 'homePhoneNumber', '', 'homephonenumber', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (164, 7, '', '1', 'homePostalCode', '', 'homepostalcode', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (165, 7, '', '1', 'homeFax', '', 'homefax', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (166, 7, '', '1', 'employeeNumber', '', 'employeenumber', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (167, 7, '', '1', 'costCenter', '', 'costcenter', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (168, 7, '', '1', 'organization', '', 'organization', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (169, 7, '', '1', 'division', '', 'division', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (170, 7, '', '1', 'departmentId', '', 'departmentid', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (171, 7, '', '1', 'department', '', 'department', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (172, 7, '', '1', 'jobTitle', '', 'jobtitle', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (173, 7, '', '1', 'jobLevel', '', 'joblevel', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (174, 7, '', '1', 'managerId', '', 'managerid', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (175, 7, '', '1', 'manager', '', 'manager', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (176, 7, '', '1', 'assistantId', '', 'assistantid', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (177, 7, '', '1', 'assistant', '', 'assistant', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (178, 7, '', '1', 'entryDate', '', 'entrydate', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (179, 7, '', '1', 'quitDate', '', 'quitdate', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (180, 7, '', '1', 'ldapDn', '', 'ldapdn', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (181, 7, '', '1', 'description', '', 'description', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (182, 7, '', '1', 'status', '', 'status', '', 'jdbc用户', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (183, 7, '', '2', 'id', '', 'id', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (184, 7, '', '2', 'orgCode', '', 'orgcode', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (185, 7, '', '2', 'orgName', '', 'orgname', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (186, 7, '', '2', 'fullName', '', 'fullname', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (187, 7, '', '2', 'parentId', '', 'parentid', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (188, 7, '', '2', 'parentCode', '', 'parentcode', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (189, 7, '', '2', 'type', '', 'type', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (190, 7, '', '2', 'codePath', '', 'codepath', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (191, 7, '', '2', 'namePath', '', 'namepath', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (192, 7, '', '2', 'level', '', 'level', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (193, 7, '', '2', 'hasChild', '', 'haschild', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (194, 7, '', '2', 'division', '', 'division', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (195, 7, '', '2', 'country', '', 'country', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (196, 7, '', '2', 'region', '', 'region', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (197, 7, '', '2', 'locality', '', 'locality', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (198, 7, '', '2', 'street', '', 'street', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (199, 7, '', '2', 'address', '', 'address', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (200, 7, '', '2', 'contact', '', 'contact', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (201, 7, '', '2', 'postalCode', '', 'postalcode', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (202, 7, '', '2', 'phone', '', 'phone', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (203, 7, '', '2', 'fax', '', 'fax', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (204, 7, '', '2', 'email', '', 'email', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (205, 7, '', '2', 'sortIndex', '', 'sortindex', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (206, 7, '', '2', 'ldapDn', '', 'ldapdn', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (207, 7, '', '2', 'description', '', 'description', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (208, 7, '', '2', 'status', '', 'status', '', 'jdbc组织', 0, NULL, 0, NULL); +INSERT INTO `sync_job_config_field` VALUES (209, 6, '', '1', 'departmentId', '', 'objectId', '', '飞书用户', 0, NULL, 0, NULL); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/summer-ospp/2024/SyncMapper/synchronizer-user-guide.pdf b/summer-ospp/2024/SyncMapper/synchronizer-user-guide.pdf new file mode 100644 index 000000000..f7ba52e7b Binary files /dev/null and b/summer-ospp/2024/SyncMapper/synchronizer-user-guide.pdf differ