MaxKey 3 роки тому
батько
коміт
be44a579c6
27 змінених файлів з 1100 додано та 192 видалено
  1. 1 1
      maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/SocialSignOnEndpoint.java
  2. 1 0
      maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/service/JdbcSocialsAssociateService.java
  3. 2 0
      maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/service/SocialsAssociateService.java
  4. 44 0
      maxkey-core/src/main/java/org/maxkey/entity/Organizations.java
  5. 21 1
      maxkey-core/src/main/java/org/maxkey/entity/SocialsAssociate.java
  6. 238 0
      maxkey-core/src/main/java/org/maxkey/entity/SynchroRelated.java
  7. 42 0
      maxkey-core/src/main/java/org/maxkey/entity/UserInfo.java
  8. 24 0
      maxkey-persistence/src/main/java/org/maxkey/persistence/mapper/SocialsAssociateMapper.java
  9. 34 0
      maxkey-persistence/src/main/java/org/maxkey/persistence/mapper/SynchroRelatedMapper.java
  10. 4 2
      maxkey-persistence/src/main/java/org/maxkey/persistence/service/OrganizationsService.java
  11. 42 0
      maxkey-persistence/src/main/java/org/maxkey/persistence/service/SocialsAssociatesService.java
  12. 77 0
      maxkey-persistence/src/main/java/org/maxkey/persistence/service/SynchroRelatedService.java
  13. 4 2
      maxkey-persistence/src/main/java/org/maxkey/persistence/service/UserInfoService.java
  14. 82 43
      maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/maxkey/synchronizer/activedirectory/ActiveDirectoryOrganizationService.java
  15. 21 1
      maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/maxkey/synchronizer/activedirectory/ActiveDirectoryUsersService.java
  16. 87 13
      maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/maxkey/synchronizer/dingtalk/DingtalkOrganizationService.java
  17. 37 22
      maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/maxkey/synchronizer/dingtalk/DingtalkUsersService.java
  18. 72 17
      maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/maxkey/synchronizer/feishu/FeishuOrganizationService.java
  19. 35 14
      maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/maxkey/synchronizer/feishu/FeishuUsersService.java
  20. 10 0
      maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/maxkey/synchronizer/feishu/entity/FeishuDeptsData.java
  21. 78 47
      maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/maxkey/synchronizer/ldap/LdapOrganizationService.java
  22. 19 2
      maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/maxkey/synchronizer/ldap/LdapUsersService.java
  23. 54 7
      maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/maxkey/synchronizer/workweixin/WorkweixinOrganizationService.java
  24. 26 10
      maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/maxkey/synchronizer/workweixin/WorkweixinUsersService.java
  25. 43 8
      maxkey-synchronizers/maxkey-synchronizer/src/main/java/org/maxkey/synchronizer/AbstractSynchronizerService.java
  26. 1 1
      maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/SocialSignOnListController.java
  27. 1 1
      maxkey-webs/maxkey-web-mgt/src/main/resources/templates/views/orgs/orgsUpdate.ftl

+ 1 - 1
maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/SocialSignOnEndpoint.java

@@ -23,8 +23,8 @@ package org.maxkey.authn.support.socialsignon;
 import javax.servlet.http.HttpServletRequest;
 
 import org.maxkey.authn.LoginCredential;
-import org.maxkey.authn.support.socialsignon.service.SocialsAssociate;
 import org.maxkey.constants.ConstsLoginType;
+import org.maxkey.entity.SocialsAssociate;
 import org.maxkey.entity.SocialsProvider;
 import org.maxkey.web.WebContext;
 import org.slf4j.Logger;

+ 1 - 0
maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/service/JdbcSocialsAssociateService.java

@@ -24,6 +24,7 @@ import java.util.Date;
 import java.util.List;
 
 import org.maxkey.constants.ConstsDatabase;
+import org.maxkey.entity.SocialsAssociate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.jdbc.core.JdbcTemplate;

+ 2 - 0
maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/service/SocialsAssociateService.java

@@ -19,6 +19,8 @@ package org.maxkey.authn.support.socialsignon.service;
 
 import java.util.List;
 
+import org.maxkey.entity.SocialsAssociate;
+
 
 public interface SocialsAssociateService{
 

+ 44 - 0
maxkey-core/src/main/java/org/maxkey/entity/Organizations.java

@@ -31,6 +31,9 @@ public class Organizations extends JpaBaseEntity implements Serializable {
 
     private static final long serialVersionUID = 5085413816404119803L;
     
+    public static final String CLASS_TYPE = "Organization";
+    public static final String ROOT_ORG_ID = "1";
+    
     @Id
     @Column
     @GeneratedValue(strategy = GenerationType.AUTO, generator = "snowflakeid")
@@ -99,6 +102,14 @@ public class Organizations extends JpaBaseEntity implements Serializable {
 	private String instId;
 
 	private String instName;
+	
+    String syncId;
+    
+    String syncName;
+    
+    String originId;
+    
+    String originId2;
     
     private int isPrimary = 0;
     
@@ -392,6 +403,39 @@ public class Organizations extends JpaBaseEntity implements Serializable {
 		this.instName = instName;
 	}
 
+	
+	public String getSyncId() {
+		return syncId;
+	}
+
+	public void setSyncId(String syncId) {
+		this.syncId = syncId;
+	}
+
+	public String getSyncName() {
+		return syncName;
+	}
+
+	public void setSyncName(String syncName) {
+		this.syncName = syncName;
+	}
+
+	public String getOriginId() {
+		return originId;
+	}
+
+	public void setOriginId(String originId) {
+		this.originId = originId;
+	}
+
+	public String getOriginId2() {
+		return originId2;
+	}
+
+	public void setOriginId2(String originId2) {
+		this.originId2 = originId2;
+	}
+
 	@Override
     public String toString() {
         StringBuilder builder = new StringBuilder();

+ 21 - 1
maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/service/SocialsAssociate.java → maxkey-core/src/main/java/org/maxkey/entity/SocialsAssociate.java

@@ -15,7 +15,14 @@
  */
  
 
-package org.maxkey.authn.support.socialsignon.service;
+package org.maxkey.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
 
 import org.apache.mybatis.jpa.persistence.JpaBaseEntity;
 
@@ -23,22 +30,35 @@ import org.apache.mybatis.jpa.persistence.JpaBaseEntity;
  * 
  * @author Crystal.Sea
  */
+@Entity
+@Table(name = "MXK_SOCIALS_ASSOCIATE")
 public class SocialsAssociate extends JpaBaseEntity {
 	
 	/**
 	 * 
 	 */
 	private static final long serialVersionUID = 2151179554190800162L;
+	@Id
+    @Column
+    @GeneratedValue(strategy = GenerationType.AUTO,generator = "snowflakeid")
 	private String id;
+	@Column
 	private String provider;
+	@Column
 	private String userId;
+	@Column
 	private String username;
+	@Column
 	private String socialUserId;
+	@Column
 	private String socialUserInfo;
 	private String accessToken;
 	private String exAttribute; 
+	@Column
     private String createdDate;
+    @Column
     private String updatedDate;
+    @Column
     private String instId;
 	
 	public SocialsAssociate() {}

+ 238 - 0
maxkey-core/src/main/java/org/maxkey/entity/SynchroRelated.java

@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+ 
+
+package org.maxkey.entity;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import org.apache.mybatis.jpa.persistence.JpaBaseEntity;
+import org.maxkey.util.DateUtils;
+
+/**
+ * .
+ * @author Crystal.Sea
+ * 
+ */
+
+@Entity
+@Table(name = "MXK_SYNCHRO_RELATED")
+public class SynchroRelated extends JpaBaseEntity {
+	private static final long serialVersionUID = 6993697309055585706L;
+
+	@Id
+	@Column
+	@GeneratedValue(strategy = GenerationType.AUTO, generator = "snowflakeid")
+	String id;
+	@Column
+	protected String objectId;
+	@Column
+	protected String objectName;
+	@Column
+	protected String objectDisplayName;
+	@Column
+	protected String objectType;
+	@Column
+	protected String syncId;
+	@Column
+	protected String syncName;
+	@Column
+	protected String originId;
+	@Column
+	protected String originId2;
+	@Column
+	protected String originId3;
+	@Column
+	protected String originName;
+	@Column
+	protected String instId;
+
+	protected String instName;
+	@Column
+	protected String syncTime;
+
+	public SynchroRelated() {
+		super();
+	}
+
+	public SynchroRelated(String objectId, String objectName,String objectDisplayName, String objectType, String syncId, String syncName,
+			String originId, String originName, String originId2, String originId3, String instId) {
+		super();
+		this.objectId = objectId;
+		this.objectName = objectName;
+		this.objectDisplayName = objectDisplayName;
+		this.objectType = objectType;
+		this.syncId = syncId;
+		this.syncName = syncName;
+		this.originId = originId;
+		this.originName = originName;
+		this.originId2 = originId2;
+		this.originId3 = originId3;
+		this.instId = instId;
+		this.syncTime = DateUtils.formatDateTime(new Date());
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getObjectId() {
+		return objectId;
+	}
+
+	public void setObjectId(String objectId) {
+		this.objectId = objectId;
+	}
+
+	public String getObjectName() {
+		return objectName;
+	}
+
+	public void setObjectName(String objectName) {
+		this.objectName = objectName;
+	}
+
+
+	public String getObjectDisplayName() {
+		return objectDisplayName;
+	}
+
+	public void setObjectDisplayName(String objectDisplayName) {
+		this.objectDisplayName = objectDisplayName;
+	}
+
+	public String getObjectType() {
+		return objectType;
+	}
+
+	public void setObjectType(String objectType) {
+		this.objectType = objectType;
+	}
+
+	public String getSyncId() {
+		return syncId;
+	}
+
+	public void setSyncId(String syncId) {
+		this.syncId = syncId;
+	}
+
+	public String getSyncName() {
+		return syncName;
+	}
+
+	public void setSyncName(String syncName) {
+		this.syncName = syncName;
+	}
+
+	public String getOriginId() {
+		return originId;
+	}
+
+	public void setOriginId(String originId) {
+		this.originId = originId;
+	}
+
+	public String getOriginName() {
+		return originName;
+	}
+
+	public void setOriginName(String originName) {
+		this.originName = originName;
+	}
+
+	public String getOriginId2() {
+		return originId2;
+	}
+
+	public void setOriginId2(String originId2) {
+		this.originId2 = originId2;
+	}
+
+	public String getOriginId3() {
+		return originId3;
+	}
+
+	public void setOriginId3(String originId3) {
+		this.originId3 = originId3;
+	}
+
+	public String getInstId() {
+		return instId;
+	}
+
+	public void setInstId(String instId) {
+		this.instId = instId;
+	}
+
+	public String getInstName() {
+		return instName;
+	}
+
+	public void setInstName(String instName) {
+		this.instName = instName;
+	}
+
+	public String getSyncTime() {
+		return syncTime;
+	}
+
+	public void setSyncTime(String syncTime) {
+		this.syncTime = syncTime;
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder builder = new StringBuilder();
+		builder.append("SynchroRelated [id=");
+		builder.append(id);
+		builder.append(", objectId=");
+		builder.append(objectId);
+		builder.append(", objectName=");
+		builder.append(objectName);
+		builder.append(", objectType=");
+		builder.append(objectType);
+		builder.append(", syncId=");
+		builder.append(syncId);
+		builder.append(", syncName=");
+		builder.append(syncName);
+		builder.append(", originId=");
+		builder.append(originId);
+		builder.append(", originId2=");
+		builder.append(originId2);
+		builder.append(", originId3=");
+		builder.append(originId3);
+		builder.append(", instId=");
+		builder.append(instId);
+		builder.append(", instName=");
+		builder.append(instName);
+		builder.append(", syncTime=");
+		builder.append(syncTime);
+		builder.append("]");
+		return builder.toString();
+	}
+
+}

+ 42 - 0
maxkey-core/src/main/java/org/maxkey/entity/UserInfo.java

@@ -44,6 +44,8 @@ import org.springframework.web.multipart.MultipartFile;
 public class UserInfo extends JpaBaseEntity {
     private static final long serialVersionUID = 6402443942083382236L;
     
+    public static final String CLASS_TYPE = "UserInfo";
+    
     public  static final String DEFAULT_PASSWORD_SUFFIX = "MaxKey@888";
     
     //
@@ -271,6 +273,14 @@ public class UserInfo extends JpaBaseEntity {
 
 	private String instName;
 	
+    String syncId;
+    
+    String syncName;
+
+    String originId;
+
+    String originId2;
+	
     List<Organizations> depts;
     
     List<UserInfoAdjoint> adjoints;
@@ -1318,6 +1328,38 @@ public class UserInfo extends JpaBaseEntity {
 		this.passwordHistory = passwordHistory;
 	}
 
+	public String getSyncId() {
+		return syncId;
+	}
+
+	public void setSyncId(String syncId) {
+		this.syncId = syncId;
+	}
+
+	public String getSyncName() {
+		return syncName;
+	}
+
+	public void setSyncName(String syncName) {
+		this.syncName = syncName;
+	}
+
+	public String getOriginId() {
+		return originId;
+	}
+
+	public void setOriginId(String originId) {
+		this.originId = originId;
+	}
+
+	public String getOriginId2() {
+		return originId2;
+	}
+
+	public void setOriginId2(String originId2) {
+		this.originId2 = originId2;
+	}
+
 	@Override
 	public String toString() {
 		StringBuilder builder = new StringBuilder();

+ 24 - 0
maxkey-persistence/src/main/java/org/maxkey/persistence/mapper/SocialsAssociateMapper.java

@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+ 
+
+package org.maxkey.persistence.mapper;
+import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
+import org.maxkey.entity.SocialsAssociate;
+
+public interface SocialsAssociateMapper extends IJpaBaseMapper<SocialsAssociate> {
+
+}

+ 34 - 0
maxkey-persistence/src/main/java/org/maxkey/persistence/mapper/SynchroRelatedMapper.java

@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+ 
+
+/**
+ * 
+ */
+package org.maxkey.persistence.mapper;
+
+import org.apache.ibatis.annotations.Update;
+import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
+import org.maxkey.entity.SynchroRelated;
+
+/**
+ * @author Crystal.sea
+ *
+ */
+public  interface SynchroRelatedMapper extends IJpaBaseMapper<SynchroRelated> {
+	@Update("update mxk_synchro_related set synctime = #{syncTime} where id= #{id} ")
+	public int updateSyncTime(SynchroRelated synchroRelated);
+}

+ 4 - 2
maxkey-persistence/src/main/java/org/maxkey/persistence/service/OrganizationsService.java

@@ -68,11 +68,13 @@ public class OrganizationsService  extends JpaBaseService<Organizations>{
      }
  
 	 public void saveOrUpdate(Organizations organization) {
-		 if(findOne(" id = ? and instid = ?", 
+		 Organizations loadOrg =findOne(" id = ? and instid = ?", 
 					new Object[] { organization.getId().toString(), organization.getInstId() },
-                 new int[] { Types.VARCHAR, Types.VARCHAR }) == null) {
+              new int[] { Types.VARCHAR, Types.VARCHAR });
+		 if( loadOrg == null) {
 				insert(organization);
 			}else {
+				organization.setId(organization.getId());
 				update(organization);
 			}
 	 }

+ 42 - 0
maxkey-persistence/src/main/java/org/maxkey/persistence/service/SocialsAssociatesService.java

@@ -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.
+ */
+ 
+
+package org.maxkey.persistence.service;
+
+import org.apache.mybatis.jpa.persistence.JpaBaseService;
+import org.maxkey.entity.SocialsAssociate;
+import org.maxkey.persistence.mapper.SocialsAssociateMapper;
+import org.springframework.stereotype.Repository;
+
+
+@Repository
+public class SocialsAssociatesService  extends JpaBaseService<SocialsAssociate>{
+	
+	public SocialsAssociatesService() {
+		super(SocialsAssociateMapper.class);
+	}
+
+	/* (non-Javadoc)
+	 * @see com.connsec.db.service.BaseService#getMapper()
+	 */
+	@Override
+	public SocialsAssociateMapper getMapper() {
+		return (SocialsAssociateMapper)super.getMapper();
+	}
+ 
+	 
+}

+ 77 - 0
maxkey-persistence/src/main/java/org/maxkey/persistence/service/SynchroRelatedService.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright [2020] [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.
+ */
+ 
+
+package org.maxkey.persistence.service;
+
+import java.sql.Types;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.mybatis.jpa.persistence.JpaBaseService;
+import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SynchroRelated;
+import org.maxkey.entity.Synchronizers;
+import org.maxkey.persistence.mapper.SynchroRelatedMapper;
+import org.maxkey.util.DateUtils;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class SynchroRelatedService  extends JpaBaseService<SynchroRelated>{
+
+	public SynchroRelatedService() {
+		super(SynchroRelatedMapper.class);
+	}
+
+	/* (non-Javadoc)
+	 * @see com.connsec.db.service.BaseService#getMapper()
+	 */
+	@Override
+	public SynchroRelatedMapper getMapper() {
+		return (SynchroRelatedMapper)super.getMapper();
+	}
+	
+	public int updateSyncTime(SynchroRelated synchroRelated) {
+		return getMapper().updateSyncTime(synchroRelated);
+	}
+	
+	public List<SynchroRelated> findOrgs(Synchronizers synchronizer) {
+		return find(
+				"instid = ? and syncid = ? and objecttype = ? ",
+		 		new Object[] { synchronizer.getInstId() ,synchronizer.getId(),Organizations.CLASS_TYPE},
+                new int[] { Types.VARCHAR,Types.VARCHAR,Types.VARCHAR}
+				);
+	}
+	
+	public SynchroRelated findByOriginId(Synchronizers synchronizer,String originId,String classType) {
+		return findOne("instid = ? and syncId = ? and originid = ? and objecttype = ? ",
+		 		new Object[] { synchronizer.getInstId(),synchronizer.getId(),originId,classType },
+                new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,Types.VARCHAR});
+	}
+	
+	public void updateSynchroRelated(Synchronizers synchronizer,SynchroRelated synchroRelated,String classType) {
+		SynchroRelated loadSynchroRelated = 
+				findByOriginId(
+						synchronizer,synchroRelated.getOriginId(),classType );
+		if(loadSynchroRelated == null) {
+			insert(synchroRelated);
+		}else {
+			synchroRelated.setId(loadSynchroRelated.getId());
+			synchroRelated.setSyncTime(DateUtils.formatDateTime(new Date()));
+			updateSyncTime(synchroRelated);
+		}
+	}
+}

+ 4 - 2
maxkey-persistence/src/main/java/org/maxkey/persistence/service/UserInfoService.java

@@ -166,11 +166,13 @@ public class UserInfoService extends JpaBaseService<UserInfo> {
 	
 	
 	public void saveOrUpdate(UserInfo userInfo) {
-		if(findOne(" username = ? and instid = ?",
+		UserInfo loadUserInfo = findOne(" username = ? and instid = ?",
 				new Object[] { userInfo.getUsername(),userInfo.getInstId() },
-                new int[] { Types.VARCHAR,Types.VARCHAR}) == null) {
+                new int[] { Types.VARCHAR,Types.VARCHAR});
+		if(loadUserInfo == null) {
 			insert(userInfo);
 		}else {
+			userInfo.setId(loadUserInfo.getId());
 			userInfo.setPassword(null);
 			update(userInfo);
 		}

+ 82 - 43
maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/maxkey/synchronizer/activedirectory/ActiveDirectoryOrganizationService.java

@@ -30,6 +30,7 @@ import org.maxkey.constants.ConstsStatus;
 import org.maxkey.constants.ldap.OrganizationalUnit;
 import org.maxkey.entity.HistorySynchronizer;
 import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SynchroRelated;
 import org.maxkey.persistence.ldap.ActiveDirectoryUtils;
 import org.maxkey.persistence.ldap.LdapUtils;
 import org.maxkey.synchronizer.AbstractSynchronizerService;
@@ -45,51 +46,13 @@ public class ActiveDirectoryOrganizationService  extends AbstractSynchronizerSer
 	ActiveDirectoryUtils ldapUtils;
 	
 	public void sync() {
-	    loadOrgsById("1");
+		loadOrgsByInstId(this.synchronizer.getInstId(),Organizations.ROOT_ORG_ID);
 		_logger.info("Sync ActiveDirectory Organizations ...");
 		try {
-			SearchControls constraints = new SearchControls();
-			constraints.setSearchScope(ldapUtils.getSearchScope());
-			String filter = "(&(objectClass=OrganizationalUnit))";
-			if(StringUtils.isNotBlank(this.getSynchronizer().getFilters())) {
-				//filter = this.getSynchronizer().getFilters();
-			}
-			
-			NamingEnumeration<SearchResult> results = 
-						ldapUtils.getConnection().search(ldapUtils.getBaseDN(), filter, constraints);
-			
-			ArrayList<Organizations> orgsList = new ArrayList<Organizations>();
+			ArrayList<Organizations> orgsList = queryActiveDirectory();
 			int  maxLevel 		= 0;
-			long recordCount 	= 0;
-			while (null != results && results.hasMoreElements()) {
-				Object obj = results.nextElement();
-				if (obj instanceof SearchResult) {
-					SearchResult sr = (SearchResult) obj;
-					if(sr.getNameInNamespace().contains("OU=Domain Controllers")||StringUtils.isEmpty(sr.getName())) {
-					    _logger.info("Skip '' or 'OU=Domain Controllers' .");
-					    continue;
-					}
-					_logger.debug("Sync OrganizationalUnit {} , name [{}] , NameInNamespace [{}]" , 
-								    (++recordCount),sr.getName(),sr.getNameInNamespace());
-					
-					HashMap<String,Attribute> attributeMap = new HashMap<String,Attribute>();
-					NamingEnumeration<? extends Attribute>  attrs = sr.getAttributes().getAll();
-					while (null != attrs && attrs.hasMoreElements()) {
-						Attribute  objAttrs = attrs.nextElement();
-						_logger.trace("attribute {} : {}" ,
-													objAttrs.getID(), 
-													ActiveDirectoryUtils.getAttrStringValue(objAttrs)
-										);
-						attributeMap.put(objAttrs.getID().toLowerCase(), objAttrs);
-					}
-					
-					Organizations organization = buildOrganization(attributeMap,sr.getName(),sr.getNameInNamespace());
-					if(organization != null) {
-						orgsList.add(organization);
-						maxLevel = (maxLevel < organization.getLevel()) ? organization.getLevel() : maxLevel ;
-					}
-					
-				}
+			for(Organizations organization : orgsList) {
+				maxLevel = (maxLevel < organization.getLevel()) ? organization.getLevel() : maxLevel ;
 			}
 			
 			for (int level = 2 ; level <= maxLevel ; level++) {
@@ -111,7 +74,24 @@ public class ActiveDirectoryOrganizationService  extends AbstractSynchronizerSer
 						organization.setCodePath(parentOrg.getCodePath()+"/"+organization.getId());
 						_logger.info("parentNamePath " + parentNamePath+" , namePah " + organization.getNamePath());
 						
-						organizationsService.saveOrUpdate(organization);
+						//synchro Related
+						SynchroRelated synchroRelated = 
+								synchroRelatedService.findByOriginId(
+										this.synchronizer,organization.getLdapDn(),Organizations.CLASS_TYPE );
+						if(synchroRelated == null) {
+							organization.setId(organization.generateId());
+							organizationsService.insert(organization);
+							_logger.debug("Organizations : " + organization);
+							
+							synchroRelated = buildSynchroRelated(organization,organization.getLdapDn(),organization.getName());
+						}else {
+							organization.setId(synchroRelated.getObjectId());
+							organizationsService.update(organization);
+						}
+						
+						synchroRelatedService.updateSynchroRelated(
+								this.synchronizer,synchroRelated,Organizations.CLASS_TYPE);
+						
 						orgsNamePathMap.put(organization.getNamePath(), organization);
 						
 						HistorySynchronizer historySynchronizer 
@@ -137,6 +117,65 @@ public class ActiveDirectoryOrganizationService  extends AbstractSynchronizerSer
 		
 	}
 	
+	private ArrayList<Organizations> queryActiveDirectory() throws NamingException {
+		SearchControls constraints = new SearchControls();
+		constraints.setSearchScope(ldapUtils.getSearchScope());
+		String filter = "(&(objectClass=OrganizationalUnit))";
+		if(StringUtils.isNotBlank(this.getSynchronizer().getFilters())) {
+			//filter = this.getSynchronizer().getFilters();
+		}
+		
+		NamingEnumeration<SearchResult> results = 
+					ldapUtils.getConnection().search(ldapUtils.getBaseDN(), filter, constraints);
+		
+		ArrayList<Organizations> orgsList = new ArrayList<Organizations>();
+		long recordCount 	= 0;
+		while (null != results && results.hasMoreElements()) {
+			Object obj = results.nextElement();
+			if (obj instanceof SearchResult) {
+				SearchResult sr = (SearchResult) obj;
+				if(sr.getNameInNamespace().contains("OU=Domain Controllers")||StringUtils.isEmpty(sr.getName())) {
+				    _logger.info("Skip '' or 'OU=Domain Controllers' .");
+				    continue;
+				}
+				_logger.debug("Sync OrganizationalUnit {} , name [{}] , NameInNamespace [{}]" , 
+							    (++recordCount),sr.getName(),sr.getNameInNamespace());
+				
+				HashMap<String,Attribute> attributeMap = new HashMap<String,Attribute>();
+				NamingEnumeration<? extends Attribute>  attrs = sr.getAttributes().getAll();
+				while (null != attrs && attrs.hasMoreElements()) {
+					Attribute  objAttrs = attrs.nextElement();
+					_logger.trace("attribute {} : {}" ,
+												objAttrs.getID(), 
+												ActiveDirectoryUtils.getAttrStringValue(objAttrs)
+									);
+					attributeMap.put(objAttrs.getID().toLowerCase(), objAttrs);
+				}
+				
+				Organizations organization = buildOrganization(attributeMap,sr.getName(),sr.getNameInNamespace());
+				if(organization != null) {
+					orgsList.add(organization);
+				}
+			}
+		}
+		return orgsList;
+	}
+	
+	public SynchroRelated buildSynchroRelated(Organizations organization,String ldapDN,String name) {
+		return new SynchroRelated(
+					organization.getId(),
+					organization.getName(),
+					organization.getName(),
+					Organizations.CLASS_TYPE,
+					synchronizer.getId(),
+					synchronizer.getName(),
+					ldapDN,
+					name,
+					"",
+					organization.getParentId(),
+					synchronizer.getInstId());
+	}
+	
 	public Organizations buildOrganization(HashMap<String,Attribute> attributeMap,String name,String nameInNamespace) {
 		try {
 		    Organizations org = new Organizations();

+ 21 - 1
maxkey-synchronizers/maxkey-synchronizer-activedirectory/src/main/java/org/maxkey/synchronizer/activedirectory/ActiveDirectoryUsersService.java

@@ -27,8 +27,10 @@ import javax.naming.directory.SearchResult;
 import org.apache.commons.lang3.StringUtils;
 import org.maxkey.constants.ConstsStatus;
 import org.maxkey.constants.ldap.ActiveDirectoryUser;
+import org.maxkey.crypto.DigestUtils;
 import org.maxkey.entity.HistorySynchronizer;
 import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SynchroRelated;
 import org.maxkey.entity.UserInfo;
 import org.maxkey.persistence.ldap.ActiveDirectoryUtils;
 import org.maxkey.persistence.ldap.LdapUtils;
@@ -46,7 +48,7 @@ public class ActiveDirectoryUsersService extends AbstractSynchronizerService
 	
 	public void sync() {
 		_logger.info("Sync ActiveDirectory Users...");
-		loadOrgsById("1");
+		loadOrgsByInstId(this.synchronizer.getInstId(),Organizations.ROOT_ORG_ID);
 		try {
 			SearchControls constraints = new SearchControls();
 			constraints.setSearchScope(ldapUtils.getSearchScope());
@@ -79,11 +81,29 @@ public class ActiveDirectoryUsersService extends AbstractSynchronizerService
 						attributeMap.put(objAttrs.getID().toLowerCase(), objAttrs);
 					}
 					
+					String originId = DigestUtils.md5B64(sr.getNameInNamespace());
+					
 					UserInfo userInfo =buildUserInfo(attributeMap,sr.getName(),sr.getNameInNamespace());
 					if(userInfo != null) {
 						userInfo.setPassword(userInfo.getUsername() + UserInfo.DEFAULT_PASSWORD_SUFFIX);
 						userInfoService.saveOrUpdate(userInfo);
 						_logger.info("userInfo " + userInfo);
+						
+						SynchroRelated synchroRelated = new SynchroRelated(
+								userInfo.getId(),
+								userInfo.getUsername(),
+								userInfo.getDisplayName(),
+								UserInfo.CLASS_TYPE,
+								synchronizer.getId(),
+								synchronizer.getName(),
+								originId,
+								userInfo.getDisplayName(),
+								"",
+								"",
+								synchronizer.getInstId());
+						
+						synchroRelatedService.updateSynchroRelated(
+								this.synchronizer,synchroRelated,UserInfo.CLASS_TYPE);
 					}
 				}
 			}

+ 87 - 13
maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/maxkey/synchronizer/dingtalk/DingtalkOrganizationService.java

@@ -17,12 +17,12 @@
 
 package org.maxkey.synchronizer.dingtalk;
 
-import java.util.HashMap;
 import java.util.NoSuchElementException;
 import java.util.concurrent.LinkedBlockingQueue;
 
 import org.maxkey.constants.ConstsStatus;
 import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SynchroRelated;
 import org.maxkey.synchronizer.AbstractSynchronizerService;
 import org.maxkey.synchronizer.ISynchronizerService;
 import org.slf4j.Logger;
@@ -30,7 +30,9 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 import com.dingtalk.api.DefaultDingTalkClient;
 import com.dingtalk.api.DingTalkClient;
+import com.dingtalk.api.request.OapiV2DepartmentGetRequest;
 import com.dingtalk.api.request.OapiV2DepartmentListsubRequest;
+import com.dingtalk.api.response.OapiV2DepartmentGetResponse;
 import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
 import com.dingtalk.api.response.OapiV2DepartmentListsubResponse.DeptBaseResponse;
 import com.taobao.api.ApiException;
@@ -39,24 +41,67 @@ import com.taobao.api.ApiException;
 public class DingtalkOrganizationService  extends AbstractSynchronizerService implements ISynchronizerService{
 	final static Logger _logger = LoggerFactory.getLogger(DingtalkOrganizationService.class);
 	
+	static Long ROOT_DEPT_ID = 1L;
+	
 	String access_token;
 	
 	public void sync() {
 		_logger.info("Sync Dingtalk Organizations ...");
 		LinkedBlockingQueue<Long> deptsQueue = new LinkedBlockingQueue<Long>();
-		deptsQueue.add(1L);
-		HashMap<Long,DeptBaseResponse> deptMap = new HashMap<Long,DeptBaseResponse>();
+		deptsQueue.add(ROOT_DEPT_ID);
 		try {
+			//root
+			Organizations rootOrganization = organizationsService.get(Organizations.ROOT_ORG_ID);
+			OapiV2DepartmentGetResponse rootDeptRsp = requestDepartment(access_token,ROOT_DEPT_ID);
+			_logger.debug("root dept   deptId {} , name {} ,  parentId {}" 
+							,rootDeptRsp.getResult().getDeptId(), 
+							rootDeptRsp.getResult().getName(), 
+							rootDeptRsp.getResult().getParentId());
+			//root
+			SynchroRelated rootSynchroRelated = buildSynchroRelated(rootOrganization,
+					rootDeptRsp.getResult().getDeptId()+"", 
+					rootDeptRsp.getResult().getName(), 
+					rootDeptRsp.getResult().getParentId()+"");
+			
+			synchroRelatedService.updateSynchroRelated(
+					this.synchronizer,rootSynchroRelated,Organizations.CLASS_TYPE);
+			
 			while(deptsQueue.element() != null) {
 				OapiV2DepartmentListsubResponse rsp = requestDepartmentList(access_token,deptsQueue.poll());
 				
 				for(DeptBaseResponse dept : rsp.getResult()) {
-					_logger.info("dept : " + dept.getDeptId()+" "+ dept.getName()+" "+ dept.getParentId());
+					_logger.debug("dept  deptId {} , name {} ,  parentId {} " , 
+							dept.getDeptId(), 
+							dept.getName(), 
+							dept.getParentId());
+					
 					deptsQueue.add(dept.getDeptId());
-					deptMap.put(dept.getDeptId(), dept);
-					Organizations organization = buildOrganization(dept,deptMap.get(dept.getParentId()));
-					organizationsService.saveOrUpdate(organization);
-					_logger.info("Organizations : " + organization);
+
+					//synchro Related
+					SynchroRelated synchroRelated = 
+							synchroRelatedService.findByOriginId(
+									this.synchronizer,dept.getDeptId() + "",Organizations.CLASS_TYPE );
+					
+					Organizations organization = buildOrganization(dept);
+					if(synchroRelated == null) {
+						organization.setId(organization.generateId());
+						organizationsService.insert(organization);
+						_logger.debug("Organizations : " + organization);
+						
+						synchroRelated = buildSynchroRelated(organization,
+								dept.getDeptId() + "", 
+								dept.getName(), 
+								dept.getParentId() + "");
+						
+					}else {
+						organization.setId(synchroRelated.getObjectId());
+						organizationsService.update(organization);
+					}
+					
+					synchroRelatedService.updateSynchroRelated(
+							this.synchronizer,synchroRelated,Organizations.CLASS_TYPE);
+					
+					_logger.debug("Organizations : " + organization);
 				}
 			}
 		} catch (ApiException e) {
@@ -73,19 +118,48 @@ public class DingtalkOrganizationService  extends AbstractSynchronizerService im
 		req.setDeptId(deptId);
 		req.setLanguage("zh_CN");
 		OapiV2DepartmentListsubResponse rspDepts = client.execute(req, access_token);
-		_logger.info("response : " + rspDepts.getBody());
+		_logger.trace("response : " + rspDepts.getBody());
 		return rspDepts;
 	}
 	
-	public Organizations buildOrganization(DeptBaseResponse dept,DeptBaseResponse parentDept) {
+	public OapiV2DepartmentGetResponse requestDepartment(String access_token,Long deptId) throws ApiException {
+		DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/get");
+		OapiV2DepartmentGetRequest req = new OapiV2DepartmentGetRequest();
+		req.setDeptId(deptId);
+		req.setLanguage("zh_CN");
+		OapiV2DepartmentGetResponse rspDepts = client.execute(req, access_token);
+		_logger.trace("response : " + rspDepts.getBody());
+		return rspDepts;
+	}
+	
+	public SynchroRelated buildSynchroRelated(Organizations organization,String deptId,String name,String parentId) {
+		return new SynchroRelated(
+				organization.getId(),
+				organization.getName(),
+				organization.getName(),
+				Organizations.CLASS_TYPE,
+				synchronizer.getId(),
+				synchronizer.getName(),
+				deptId+"",
+				name,
+				"",
+				parentId,
+				synchronizer.getInstId());
+	}
+	
+	public Organizations buildOrganization(DeptBaseResponse dept) {
+		//Parent
+		SynchroRelated synchroRelatedParent = 
+				synchroRelatedService.findByOriginId(
+				this.synchronizer,dept.getParentId() + "",Organizations.CLASS_TYPE);
 		Organizations org = new Organizations();
 		org.setId(dept.getDeptId()+"");
 		org.setCode(dept.getDeptId()+"");
 		org.setName(dept.getName());
-		org.setParentId(dept.getParentId()+"");
 		org.setParentCode(dept.getParentId()+"");
-		if(parentDept != null) {
-			org.setParentName(parentDept.getName());
+		if(synchroRelatedParent != null) {
+			org.setParentId(synchroRelatedParent.getObjectId());
+			org.setParentName(synchroRelatedParent.getObjectName());
 		}
 		org.setInstId(this.synchronizer.getInstId());
 		org.setStatus(ConstsStatus.ACTIVE);

+ 37 - 22
maxkey-synchronizers/maxkey-synchronizer-dingtalk/src/main/java/org/maxkey/synchronizer/dingtalk/DingtalkUsersService.java

@@ -17,14 +17,13 @@
 
 package org.maxkey.synchronizer.dingtalk;
 
-import java.sql.Types;
 import java.util.List;
 
 import org.apache.commons.lang3.StringUtils;
 import org.joda.time.DateTime;
 import org.joda.time.format.DateTimeFormat;
 import org.maxkey.constants.ConstsStatus;
-import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SynchroRelated;
 import org.maxkey.entity.UserInfo;
 import org.maxkey.synchronizer.AbstractSynchronizerService;
 import org.maxkey.synchronizer.ISynchronizerService;
@@ -46,17 +45,14 @@ public class DingtalkUsersService  extends AbstractSynchronizerService implement
 	public void sync() {
 		_logger.info("Sync Dingtalk Users...");
 		try {
+			List<SynchroRelated> synchroRelateds = 
+					synchroRelatedService.findOrgs(this.synchronizer);
 			
-			 List<Organizations> organizations = 
-					 organizationsService.find("instid = ?",
-									 		new Object[] { this.synchronizer.getInstId() },
-					                        new int[] { Types.VARCHAR});
-			 
-			for(Organizations dept : organizations) {
+			for(SynchroRelated relatedOrg : synchroRelateds) {
 				DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/list");
 				OapiV2UserListRequest req = new OapiV2UserListRequest();
-				_logger.info("DingTalk deptId : {}" , dept.getCode());
-				req.setDeptId(Long.parseLong(dept.getCode()));
+				_logger.debug("DingTalk deptId : {}" , relatedOrg.getOriginId());
+				req.setDeptId(Long.parseLong(relatedOrg.getOriginId()));
 				req.setCursor(0L);
 				req.setSize(100L);
 				req.setOrderField("modify_desc");
@@ -68,10 +64,28 @@ public class DingtalkUsersService  extends AbstractSynchronizerService implement
 				if(rsp.getErrcode()==0) {
 					for(ListUserResponse user :rsp.getResult().getList()) {
 						_logger.debug("name : {} , {} , {}", user.getName(),user.getLoginId(),user.getUserid());
-						UserInfo userInfo  = buildUserInfo(user);
+						
+						UserInfo userInfo  = buildUserInfo(user,relatedOrg);
 						_logger.trace("userInfo {}" , userInfo);
 						userInfo.setPassword(userInfo.getUsername() + UserInfo.DEFAULT_PASSWORD_SUFFIX);
 						userInfoService.saveOrUpdate(userInfo);
+						
+						SynchroRelated synchroRelated = new SynchroRelated(
+								userInfo.getId(),
+								userInfo.getUsername(),
+								userInfo.getDisplayName(),
+								UserInfo.CLASS_TYPE,
+								synchronizer.getId(),
+								synchronizer.getName(),
+								user.getUnionid(),
+								user.getName(),
+								user.getUserid(),
+								"",
+								synchronizer.getInstId());
+						synchroRelatedService.updateSynchroRelated(
+								this.synchronizer,synchroRelated,UserInfo.CLASS_TYPE);
+						
+						socialsAssociate(synchroRelated,"dingtalk");
 					}
 				}
 			}
@@ -83,24 +97,25 @@ public class DingtalkUsersService  extends AbstractSynchronizerService implement
 		
 	}
 	
-	public UserInfo buildUserInfo(ListUserResponse user) {
+	public UserInfo buildUserInfo(ListUserResponse user,SynchroRelated relatedOrg) {
 		UserInfo userInfo = new  UserInfo();
 
-		userInfo.setUsername(user.getUserid());//閻ц缍嶉崥锟�
-		userInfo.setNickName(user.getName());//閻€劍鍩涢崥锟�
-		userInfo.setDisplayName(user.getName());//閻€劍鍩涢崥锟�
-		userInfo.setFormattedName(user.getName());//閻€劍鍩涢崥锟�
+		userInfo.setUsername(user.getUserid());
+		userInfo.setNickName(user.getName());
+		userInfo.setDisplayName(user.getName());
+		userInfo.setFormattedName(user.getName());
 		
 		userInfo.setEmail(StringUtils.isBlank(user.getEmail())? user.getUserid() +"@maxkey.top":user.getEmail());
 		userInfo.setEntryDate(new DateTime(user.getHiredDate()).toString(DateTimeFormat.forPattern("yyyy-MM-dd")));
-		userInfo.setMobile(user.getMobile());//閹靛婧�
+		userInfo.setMobile(user.getMobile());
 		
-		userInfo.setDepartmentId(user.getDeptIdList().get(0)+"");
+		userInfo.setDepartmentId(relatedOrg.getObjectId()+"");
+		userInfo.setDepartment(relatedOrg.getObjectName());
 		userInfo.setEmployeeNumber(user.getJobNumber());
-		userInfo.setJobTitle(user.getTitle());//閼卞苯濮�
-		userInfo.setWorkEmail(user.getOrgEmail());//瀹搞儰缍旈柇顔绘
-		userInfo.setWorkPhoneNumber(user.getTelephone());//閸忣剙寰冮悽浣冪樈
-		userInfo.setWorkOfficeName(user.getWorkPlace());//閸旂偛鍙曠�癸拷
+		userInfo.setJobTitle(user.getTitle());
+		userInfo.setWorkEmail(user.getOrgEmail());
+		userInfo.setWorkPhoneNumber(user.getTelephone());
+		userInfo.setWorkOfficeName(user.getWorkPlace());
 		if(user.getActive()) {
 			userInfo.setStatus(ConstsStatus.ACTIVE);
 		}else {

+ 72 - 17
maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/maxkey/synchronizer/feishu/FeishuOrganizationService.java

@@ -23,6 +23,7 @@ import java.util.concurrent.LinkedBlockingQueue;
 
 import org.maxkey.constants.ConstsStatus;
 import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SynchroRelated;
 import org.maxkey.synchronizer.AbstractSynchronizerService;
 import org.maxkey.synchronizer.ISynchronizerService;
 import org.maxkey.synchronizer.feishu.entity.FeishuDepts;
@@ -40,30 +41,55 @@ public class FeishuOrganizationService extends AbstractSynchronizerService imple
 	
 	String access_token;
 	
-	static String DEPTS_URL="https://open.feishu.cn/open-apis/contact/v3/departments/%s/children?page_size=50";
-	
+	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";
+	static String ROOT_DEPT_ID = "0";
 	public void sync() {
 		_logger.info("Sync Feishu Organizations ...");
 
 		LinkedBlockingQueue<String> deptsQueue = new LinkedBlockingQueue<String>();
-		deptsQueue.add("0");
-		HashMap<String,FeishuDepts> deptMap = new HashMap<String,FeishuDepts>();
+		
+		deptsQueue.add(ROOT_DEPT_ID);
+		//root
+		FeishuDeptsResponse rspRoot = requestDepartment(ROOT_DEPT_URL,ROOT_DEPT_ID,access_token);
+		Organizations rootOrganization = organizationsService.get(Organizations.ROOT_ORG_ID);
+		SynchroRelated rootSynchroRelated = buildSynchroRelated(rootOrganization,rspRoot.getData().getDepartment());
+				
+		synchroRelatedService.updateSynchroRelated(
+				this.synchronizer,rootSynchroRelated,Organizations.CLASS_TYPE);
+		
+		//child
 		try {
 			while(deptsQueue.element() != null) {
 				FeishuDeptsResponse rsp = requestDepartmentList(access_token,deptsQueue.poll());
 				if(rsp.getCode() == 0 && rsp.getData().getItems() != null) {
 					for(FeishuDepts dept : rsp.getData().getItems()) {
-						_logger.info("dept : id {} , Parent {} , Name {} , od {}" ,
+						_logger.debug("dept : id {} , Parent {} , Name {} , od {}" ,
 								 dept.getDepartment_id(),
 								 dept.getParent_department_id(),
 								 dept.getName(),
 								 dept.getOpen_department_id()
 								 );
 						deptsQueue.add(dept.getOpen_department_id());
-						deptMap.put(dept.getOpen_department_id(), dept);
-						Organizations organization = buildOrganization(dept,deptMap.get(dept.getParent_department_id()));
-						organizationsService.saveOrUpdate(organization);
-						_logger.info("Organizations : " + organization);
+						//synchro Related
+						SynchroRelated synchroRelated = 
+								synchroRelatedService.findByOriginId(
+										this.synchronizer,dept.getOpen_department_id(),Organizations.CLASS_TYPE );
+						Organizations organization = buildOrganization(dept);
+						if(synchroRelated == null) {
+							organization.setId(organization.generateId());
+							organizationsService.insert(organization);
+							_logger.debug("Organizations : " + organization);
+							synchroRelated = buildSynchroRelated(organization,dept);
+							
+						}else {
+							organization.setId(synchroRelated.getObjectId());
+							organizationsService.update(organization);
+						}
+						
+						
+						synchroRelatedService.updateSynchroRelated(
+								this.synchronizer,synchroRelated,Organizations.CLASS_TYPE);
 					}
 				}
 			}
@@ -80,21 +106,50 @@ public class FeishuOrganizationService extends AbstractSynchronizerService imple
 		String responseBody = request.get(String.format(DEPTS_URL, deptId),headers);
 		FeishuDeptsResponse deptsResponse  =JsonUtils.gson2Object(responseBody, FeishuDeptsResponse.class);
 		
-		_logger.info("response : " + responseBody);
+		_logger.trace("response : " + responseBody);
+
+		return deptsResponse;
+	}
+	
+	public FeishuDeptsResponse requestDepartment(String url ,String deptId ,String access_token) {
+		HttpRequestAdapter request =new HttpRequestAdapter();
+		HashMap<String,String> headers =new HashMap<String,String>();
+		headers.put("Authorization", AuthorizationHeaderUtils.createBearer(access_token));
+		String responseBody = request.get(String.format(url, deptId),headers);
+		FeishuDeptsResponse deptsResponse  =JsonUtils.gson2Object(responseBody, FeishuDeptsResponse.class);
+		
+		_logger.trace("response : " + responseBody);
 
 		return deptsResponse;
 	}
 	
-	public Organizations buildOrganization(FeishuDepts dept,FeishuDepts parentDept) {
+	public SynchroRelated buildSynchroRelated(Organizations org,FeishuDepts dept) {
+		return  new SynchroRelated(
+				org.getId(),
+				org.getName(),
+				org.getName(),
+				Organizations.CLASS_TYPE,
+				synchronizer.getId(),
+				synchronizer.getName(),
+				dept.getOpen_department_id(),
+				dept.getName(),
+				dept.getDepartment_id(),
+				dept.getParent_department_id(),
+				synchronizer.getInstId());
+	}
+	
+	public Organizations buildOrganization(FeishuDepts dept) {
+		//Parent
+		SynchroRelated synchroRelatedParent = 
+				synchroRelatedService.findByOriginId(
+				this.synchronizer,dept.getParent_department_id(),Organizations.CLASS_TYPE);
+		
 		Organizations org = new Organizations();
-		org.setId(dept.getOpen_department_id()+"");
 		org.setCode(dept.getDepartment_id()+"");
 		org.setName(dept.getName());
-		if(parentDept == null) {
-			org.setParentId("1");
-		}else {
-			org.setParentId(parentDept.getOpen_department_id()+"");
-		}
+		org.setFullName(dept.getName());
+		org.setParentId(synchroRelatedParent.getObjectId());
+		org.setParentName(synchroRelatedParent.getObjectName());
 		org.setSortIndex(Integer.parseInt(dept.getOrder()));
 		org.setInstId(this.synchronizer.getInstId());
 		org.setStatus(ConstsStatus.ACTIVE);

+ 35 - 14
maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/maxkey/synchronizer/feishu/FeishuUsersService.java

@@ -17,12 +17,11 @@
 
 package org.maxkey.synchronizer.feishu;
 
-import java.sql.Types;
 import java.util.HashMap;
 import java.util.List;
 
 import org.maxkey.constants.ConstsStatus;
-import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SynchroRelated;
 import org.maxkey.entity.UserInfo;
 import org.maxkey.synchronizer.AbstractSynchronizerService;
 import org.maxkey.synchronizer.ISynchronizerService;
@@ -46,23 +45,41 @@ public class FeishuUsersService extends AbstractSynchronizerService implements I
 	public void sync() {
 		_logger.info("Sync Feishu Users...");
 		try {
-			List<Organizations> organizations = 
-					 organizationsService.find("instid = ?",
-									 		new Object[] { this.synchronizer.getInstId() },
-					                        new int[] { Types.VARCHAR});
-			for(Organizations dept : organizations) {
+			List<SynchroRelated> synchroRelateds = 
+					synchroRelatedService.findOrgs(this.synchronizer);
+					
+			for(SynchroRelated relatedOrg : synchroRelateds) {
 				HttpRequestAdapter request =new HttpRequestAdapter();
 				HashMap<String,String> headers =new HashMap<String,String>();
 				headers.put("Authorization", AuthorizationHeaderUtils.createBearer(access_token));
-				String responseBody = request.get(String.format(USERS_URL,dept.getId()),headers);
+				String responseBody = request.get(String.format(USERS_URL,relatedOrg.getOriginId()),headers);
 				FeishuUsersResponse usersResponse  =JsonUtils.gson2Object(responseBody, FeishuUsersResponse.class);
-				_logger.info("response : " + responseBody);
+				_logger.trace("response : " + responseBody);
 				if(usersResponse.getCode() == 0 && usersResponse.getData().getItems() != null) {
-					for(FeishuUsers user : usersResponse.getData().getItems()) {
-						UserInfo userInfo  = buildUserInfo(user);
-						_logger.info("userInfo : " + userInfo);
+					for(FeishuUsers feiShuUser : usersResponse.getData().getItems()) {
+						UserInfo userInfo  = buildUserInfo(feiShuUser,relatedOrg);
+						_logger.debug("userInfo : " + userInfo);
 						userInfo.setPassword(userInfo.getUsername() + UserInfo.DEFAULT_PASSWORD_SUFFIX);
 						userInfoService.saveOrUpdate(userInfo);
+						
+						SynchroRelated synchroRelated = new SynchroRelated(
+								userInfo.getId(),
+								userInfo.getUsername(),
+								userInfo.getDisplayName(),
+								UserInfo.CLASS_TYPE,
+								synchronizer.getId(),
+								synchronizer.getName(),
+								feiShuUser.getOpen_id(),
+								feiShuUser.getName(),
+								feiShuUser.getUser_id(),
+								feiShuUser.getUnion_id(),
+								synchronizer.getInstId());
+						synchroRelatedService.updateSynchroRelated(
+								this.synchronizer,synchroRelated,UserInfo.CLASS_TYPE);
+						
+						synchroRelated.setOriginId(feiShuUser.getUnion_id());
+						socialsAssociate(synchroRelated,"feishu");
+						
 					}
 				}
 			}
@@ -77,8 +94,9 @@ public class FeishuUsersService extends AbstractSynchronizerService implements I
 		
 	}
 
-	public UserInfo buildUserInfo(FeishuUsers user) {
+	public UserInfo buildUserInfo(FeishuUsers user,SynchroRelated relatedOrg) {
 		UserInfo userInfo = new  UserInfo();
+		userInfo.setId(userInfo.generateId());
 		userInfo.setUsername(user.getUser_id());//账号
 		userInfo.setNickName(user.getNickname());//名字
 		userInfo.setDisplayName(user.getName());//名字
@@ -89,7 +107,10 @@ public class FeishuUsersService extends AbstractSynchronizerService implements I
 		
 		userInfo.setEmployeeNumber(user.getEmployee_no());
 		userInfo.setWorkPhoneNumber(user.getMobile());//工作电话
-		userInfo.setDepartmentId(user.getDepartment_ids()[0]+"");
+		
+		userInfo.setDepartmentId(relatedOrg.getObjectId());
+		userInfo.setDepartment(relatedOrg.getObjectName());
+		
 		userInfo.setJobTitle(user.getJob_title());//职务
 		userInfo.setWorkAddressFormatted(user.getWork_station());//工作地点
 

+ 10 - 0
maxkey-synchronizers/maxkey-synchronizer-feishu/src/main/java/org/maxkey/synchronizer/feishu/entity/FeishuDeptsData.java

@@ -26,6 +26,8 @@ public class FeishuDeptsData extends ResponseData {
 	String page_token;
 	ArrayList<FeishuDepts> items;
 
+	FeishuDepts department;
+	
 	public boolean isHas_more() {
 		return has_more;
 	}
@@ -50,6 +52,14 @@ public class FeishuDeptsData extends ResponseData {
 		this.items = items;
 	}
 
+	public FeishuDepts getDepartment() {
+		return department;
+	}
+
+	public void setDepartment(FeishuDepts department) {
+		this.department = department;
+	}
+
 	public FeishuDeptsData() {
 		super();
 	}

+ 78 - 47
maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/maxkey/synchronizer/ldap/LdapOrganizationService.java

@@ -31,6 +31,7 @@ import org.maxkey.constants.ConstsStatus;
 import org.maxkey.constants.ldap.OrganizationalUnit;
 import org.maxkey.entity.HistorySynchronizer;
 import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SynchroRelated;
 import org.maxkey.persistence.ldap.LdapUtils;
 import org.maxkey.synchronizer.AbstractSynchronizerService;
 import org.maxkey.synchronizer.ISynchronizerService;
@@ -46,44 +47,12 @@ public class LdapOrganizationService extends AbstractSynchronizerService  implem
 	
 	public void sync() {
 		_logger.info("Sync Ldap Organizations ...");
-		loadOrgsById("1");
+		loadOrgsByInstId(this.synchronizer.getInstId(),Organizations.ROOT_ORG_ID);
 		try {
-			SearchControls constraints = new SearchControls();
-			constraints.setSearchScope(ldapUtils.getSearchScope());
-			String filter = "(&(objectClass=OrganizationalUnit))";
-			if(StringUtils.isNotBlank(this.getSynchronizer().getFilters())) {
-				//filter = this.getSynchronizer().getFilters();
-			}
-			NamingEnumeration<SearchResult> results = 
-					ldapUtils.getConnection().search(ldapUtils.getBaseDN(), filter , constraints);
-			
-			ArrayList<Organizations> orgsList = new ArrayList<Organizations>();
+			ArrayList<Organizations> orgsList = queryLdap();
 			int  maxLevel 		= 0;
-			long recordCount 	= 0;
-			while (null != results && results.hasMoreElements()) {
-				Object obj = results.nextElement();
-				if (obj instanceof SearchResult) {
-					SearchResult sr = (SearchResult) obj;
-					_logger.debug("Sync OrganizationalUnit {} , name [{}] , NameInNamespace [{}]" , 
-										(++recordCount),sr.getName(),sr.getNameInNamespace());
-					
-					HashMap<String,Attribute> attributeMap = new HashMap<String,Attribute>();
-					NamingEnumeration<? extends Attribute>  attrs = sr.getAttributes().getAll();
-					while (null != attrs && attrs.hasMoreElements()) {
-						Attribute  objAttrs = attrs.nextElement();
-						_logger.trace("attribute {} : {}" ,
-											objAttrs.getID(), 
-											LdapUtils.getAttrStringValue(objAttrs)
-								);
-						attributeMap.put(objAttrs.getID().toLowerCase(), objAttrs);
-					}
-					
-					Organizations organization = buildOrganization(attributeMap,sr.getName(),sr.getNameInNamespace());
-					if(organization != null) {
-						orgsList.add(organization);
-						maxLevel = (maxLevel < organization.getLevel()) ? organization.getLevel() : maxLevel ;
-					}
-				}
+			for(Organizations organization : orgsList) {
+				maxLevel = (maxLevel < organization.getLevel()) ? organization.getLevel() : maxLevel ;
 			}
 			
 			for (int level = 2 ; level <= maxLevel ; level++) {
@@ -105,7 +74,24 @@ public class LdapOrganizationService extends AbstractSynchronizerService  implem
 						organization.setCodePath(parentOrg.getCodePath()+"/"+organization.getId());
 						_logger.info("parentNamePath " + parentNamePath+" , namePah " + organization.getNamePath());
 						
-						organizationsService.saveOrUpdate(organization);
+						//synchro Related
+						SynchroRelated synchroRelated = 
+								synchroRelatedService.findByOriginId(
+										this.synchronizer,organization.getLdapDn(),Organizations.CLASS_TYPE );
+						if(synchroRelated == null) {
+							organization.setId(organization.generateId());
+							organizationsService.insert(organization);
+							_logger.debug("Organizations : " + organization);
+							
+							synchroRelated = buildSynchroRelated(organization,organization.getLdapDn(),organization.getName());
+						}else {
+							organization.setId(synchroRelated.getObjectId());
+							organizationsService.update(organization);
+						}
+						
+						synchroRelatedService.updateSynchroRelated(
+								this.synchronizer,synchroRelated,Organizations.CLASS_TYPE);
+						
 						orgsNamePathMap.put(organization.getNamePath(), organization);
 						
 						_logger.info("Organizations " + organization);
@@ -129,6 +115,61 @@ public class LdapOrganizationService extends AbstractSynchronizerService  implem
 		
 	}
 	
+	private ArrayList<Organizations> queryLdap() throws NamingException {
+		SearchControls constraints = new SearchControls();
+		constraints.setSearchScope(ldapUtils.getSearchScope());
+		String filter = "(&(objectClass=OrganizationalUnit))";
+		if(StringUtils.isNotBlank(this.getSynchronizer().getFilters())) {
+			//filter = this.getSynchronizer().getFilters();
+		}
+		NamingEnumeration<SearchResult> results = 
+				ldapUtils.getConnection().search(ldapUtils.getBaseDN(), filter , constraints);
+		
+		ArrayList<Organizations> orgsList = new ArrayList<Organizations>();
+		
+		long recordCount 	= 0;
+		while (null != results && results.hasMoreElements()) {
+			Object obj = results.nextElement();
+			if (obj instanceof SearchResult) {
+				SearchResult sr = (SearchResult) obj;
+				_logger.debug("Sync OrganizationalUnit {} , name [{}] , NameInNamespace [{}]" , 
+									(++recordCount),sr.getName(),sr.getNameInNamespace());
+				
+				HashMap<String,Attribute> attributeMap = new HashMap<String,Attribute>();
+				NamingEnumeration<? extends Attribute>  attrs = sr.getAttributes().getAll();
+				while (null != attrs && attrs.hasMoreElements()) {
+					Attribute  objAttrs = attrs.nextElement();
+					_logger.trace("attribute {} : {}" ,
+										objAttrs.getID(), 
+										LdapUtils.getAttrStringValue(objAttrs)
+							);
+					attributeMap.put(objAttrs.getID().toLowerCase(), objAttrs);
+				}
+				
+				Organizations organization = buildOrganization(attributeMap,sr.getName(),sr.getNameInNamespace());
+				if(organization != null) {
+					orgsList.add(organization);
+				}
+			}
+		}
+		return orgsList;
+	}
+	
+	public SynchroRelated buildSynchroRelated(Organizations organization,String ldapDN,String name) {
+		return new SynchroRelated(
+					organization.getId(),
+					organization.getName(),
+					organization.getName(),
+					Organizations.CLASS_TYPE,
+					synchronizer.getId(),
+					synchronizer.getName(),
+					ldapDN,
+					name,
+					"",
+					organization.getParentId(),
+					synchronizer.getInstId());
+	}
+	
 	public Organizations buildOrganization(HashMap<String,Attribute> attributeMap,String name,String nameInNamespace) {
 		try {
 			Organizations org = new Organizations();
@@ -158,16 +199,6 @@ public class LdapOrganizationService extends AbstractSynchronizerService  implem
 			org.setInstId(this.synchronizer.getInstId());
 			org.setStatus(ConstsStatus.ACTIVE);
             _logger.info("org " + org);
-            HistorySynchronizer historySynchronizer =new HistorySynchronizer();
-            historySynchronizer.setId(historySynchronizer.generateId());
-            historySynchronizer.setSyncId(this.synchronizer.getId());
-            historySynchronizer.setSyncName(this.synchronizer.getName());
-            historySynchronizer.setObjectId(org.getId());
-            historySynchronizer.setObjectName(org.getName());
-            historySynchronizer.setObjectType(Organizations.class.getSimpleName());
-            historySynchronizer.setInstId(synchronizer.getInstId());
-            historySynchronizer.setResult("success");
-            this.historySynchronizerService.insert(historySynchronizer);
             return org;
 		} catch (NamingException e) {
 			_logger.error("NamingException " , e);

+ 19 - 2
maxkey-synchronizers/maxkey-synchronizer-ldap/src/main/java/org/maxkey/synchronizer/ldap/LdapUsersService.java

@@ -26,8 +26,10 @@ import javax.naming.directory.SearchResult;
 
 import org.apache.commons.lang3.StringUtils;
 import org.maxkey.constants.ldap.InetOrgPerson;
+import org.maxkey.crypto.DigestUtils;
 import org.maxkey.entity.HistorySynchronizer;
 import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SynchroRelated;
 import org.maxkey.entity.UserInfo;
 import org.maxkey.persistence.ldap.LdapUtils;
 import org.maxkey.synchronizer.AbstractSynchronizerService;
@@ -44,7 +46,7 @@ public class LdapUsersService extends AbstractSynchronizerService  implements IS
 	
 	public void sync() {
 		_logger.info("Sync Ldap Users ...");
-		loadOrgsById("1");
+		loadOrgsByInstId(this.synchronizer.getInstId(),Organizations.ROOT_ORG_ID);
 		try {
 			SearchControls constraints = new SearchControls();
 			constraints.setSearchScope(ldapUtils.getSearchScope());
@@ -71,10 +73,25 @@ public class LdapUsersService extends AbstractSynchronizerService  implements IS
 								);
 						attributeMap.put(objAttrs.getID(), objAttrs);
 					}
-					
+					String originId = DigestUtils.md5B64(sr.getNameInNamespace());
 					UserInfo userInfo  = buildUserInfo(attributeMap,sr.getName(),sr.getNameInNamespace());
 					userInfo.setPassword(userInfo.getUsername() + UserInfo.DEFAULT_PASSWORD_SUFFIX);
 					userInfoService.saveOrUpdate(userInfo);
+					SynchroRelated synchroRelated = new SynchroRelated(
+							userInfo.getId(),
+							userInfo.getUsername(),
+							userInfo.getDisplayName(),
+							UserInfo.CLASS_TYPE,
+							synchronizer.getId(),
+							synchronizer.getName(),
+							originId,
+							userInfo.getDisplayName(),
+							"",
+							"",
+							synchronizer.getInstId());
+					
+					synchroRelatedService.updateSynchroRelated(
+							this.synchronizer,synchroRelated,UserInfo.CLASS_TYPE);
 					_logger.info("userInfo " + userInfo);
 				}
 			}

+ 54 - 7
maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/maxkey/synchronizer/workweixin/WorkweixinOrganizationService.java

@@ -19,6 +19,7 @@ package org.maxkey.synchronizer.workweixin;
 
 import org.maxkey.constants.ConstsStatus;
 import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SynchroRelated;
 import org.maxkey.synchronizer.AbstractSynchronizerService;
 import org.maxkey.synchronizer.ISynchronizerService;
 import org.maxkey.synchronizer.workweixin.entity.WorkWeixinDepts;
@@ -36,6 +37,7 @@ public class WorkweixinOrganizationService extends AbstractSynchronizerService i
 	String access_token;
 	
 	static String DEPTS_URL="https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=%s";
+	static long ROOT_DEPT_ID = 1;
 	
 	public void sync() {
 		_logger.info("Sync Workweixin Organizations ...");
@@ -44,9 +46,34 @@ public class WorkweixinOrganizationService extends AbstractSynchronizerService i
 			WorkWeixinDeptsResponse rsp = requestDepartmentList(access_token);
 			
 			for(WorkWeixinDepts dept : rsp.getDepartment()) {
-				_logger.info("dept : " + dept.getId()+" "+ dept.getName()+" "+ dept.getParentid());
-				Organizations organization = buildOrganization(dept);
-				organizationsService.saveOrUpdate(organization);
+				_logger.debug("dept : " + dept.getId()+" "+ dept.getName()+" "+ dept.getParentid());
+				//root
+				if(dept.getId() == ROOT_DEPT_ID) {
+					Organizations rootOrganization = organizationsService.get(Organizations.ROOT_ORG_ID);
+					SynchroRelated rootSynchroRelated = buildSynchroRelated(rootOrganization,dept);
+					synchroRelatedService.updateSynchroRelated(
+							this.synchronizer,rootSynchroRelated,Organizations.CLASS_TYPE);
+				}else {
+					//synchro Related
+					SynchroRelated synchroRelated = 
+							synchroRelatedService.findByOriginId(
+									this.synchronizer,dept.getId() + "",Organizations.CLASS_TYPE );
+					
+					Organizations organization = buildOrganization(dept);
+					if(synchroRelated == null) {
+						organization.setId(organization.generateId());
+						organizationsService.insert(organization);
+						_logger.debug("Organizations : " + organization);
+						
+						synchroRelated = buildSynchroRelated(organization,dept);
+					}else {
+						organization.setId(synchroRelated.getObjectId());
+						organizationsService.update(organization);
+					}
+					
+					synchroRelatedService.updateSynchroRelated(
+							this.synchronizer,synchroRelated,Organizations.CLASS_TYPE);
+				}
 			}
 
 		} catch (Exception e) {
@@ -55,23 +82,43 @@ public class WorkweixinOrganizationService extends AbstractSynchronizerService i
 		
 	}
 	
+	public SynchroRelated buildSynchroRelated(Organizations organization,WorkWeixinDepts dept) {
+		return new SynchroRelated(
+					organization.getId(),
+					organization.getName(),
+					organization.getName(),
+					Organizations.CLASS_TYPE,
+					synchronizer.getId(),
+					synchronizer.getName(),
+					dept.getId()+"",
+					dept.getName(),
+					"",
+					dept.getParentid()+"",
+					synchronizer.getInstId());
+	}
+	
 	public WorkWeixinDeptsResponse requestDepartmentList(String access_token) {
 		HttpRequestAdapter request =new HttpRequestAdapter();
 		String responseBody = request.get(String.format(DEPTS_URL, access_token));
 		WorkWeixinDeptsResponse deptsResponse  =JsonUtils.gson2Object(responseBody, WorkWeixinDeptsResponse.class);
 		
-		_logger.info("response : " + responseBody);
+		_logger.trace("response : " + responseBody);
 		for(WorkWeixinDepts dept : deptsResponse.getDepartment()) {
-			_logger.info("WorkWeixinDepts : " + dept);
+			_logger.debug("WorkWeixinDepts : " + dept);
 		}
 		return deptsResponse;
 	}
 	
 	public Organizations buildOrganization(WorkWeixinDepts dept) {
+		//Parent
+		SynchroRelated synchroRelatedParent = 
+				synchroRelatedService.findByOriginId(
+				this.synchronizer,dept.getParentid() + "",Organizations.CLASS_TYPE);
 		Organizations org = new Organizations();
-		org.setId(dept.getId()+"");
 		org.setName(dept.getName());
-		org.setParentId(dept.getParentid()+"");
+		org.setCode(dept.getId()+"");
+		org.setParentId(synchroRelatedParent.getObjectId());
+		org.setParentName(synchroRelatedParent.getObjectName());
 		org.setSortIndex(dept.getOrder());
 		org.setInstId(this.synchronizer.getInstId());
 		org.setStatus(ConstsStatus.ACTIVE);

+ 26 - 10
maxkey-synchronizers/maxkey-synchronizer-workweixin/src/main/java/org/maxkey/synchronizer/workweixin/WorkweixinUsersService.java

@@ -17,11 +17,10 @@
 
 package org.maxkey.synchronizer.workweixin;
 
-import java.sql.Types;
 import java.util.List;
 
 import org.maxkey.constants.ConstsStatus;
-import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SynchroRelated;
 import org.maxkey.entity.UserInfo;
 import org.maxkey.synchronizer.AbstractSynchronizerService;
 import org.maxkey.synchronizer.ISynchronizerService;
@@ -44,21 +43,38 @@ public class WorkweixinUsersService extends AbstractSynchronizerService implemen
 	public void sync() {
 		_logger.info("Sync Workweixin Users...");
 		try {
-			List<Organizations> organizations = 
-					 organizationsService.find("instid = ?",
-									 		new Object[] { this.synchronizer.getInstId() },
-					                        new int[] { Types.VARCHAR});
-			for(Organizations dept : organizations) {
+			List<SynchroRelated> synchroRelateds = 
+					synchroRelatedService.findOrgs(this.synchronizer);
+			
+			for(SynchroRelated relatedOrg : synchroRelateds) {
 				HttpRequestAdapter request =new HttpRequestAdapter();
-				String responseBody = request.get(String.format(USERS_URL, access_token,dept.getId()));
+				String responseBody = request.get(String.format(USERS_URL, access_token,relatedOrg.getOriginId()));
 				WorkWeixinUsersResponse usersResponse  =JsonUtils.gson2Object(responseBody, WorkWeixinUsersResponse.class);
-				_logger.info("response : " + responseBody);
+				_logger.trace("response : " + responseBody);
 				
 				for(WorkWeixinUsers user : usersResponse.getUserlist()) {
 					UserInfo userInfo  = buildUserInfo(user);
-					_logger.info("userInfo : " + userInfo);
+					_logger.debug("userInfo : " + userInfo);
 					userInfo.setPassword(userInfo.getUsername() + UserInfo.DEFAULT_PASSWORD_SUFFIX);
 					userInfoService.saveOrUpdate(userInfo);
+					
+					SynchroRelated synchroRelated = new SynchroRelated(
+							userInfo.getId(),
+							userInfo.getUsername(),
+							userInfo.getDisplayName(),
+							UserInfo.CLASS_TYPE,
+							synchronizer.getId(),
+							synchronizer.getName(),
+							user.getUserid(),
+							user.getName(),
+							user.getUserid(),
+							"",
+							synchronizer.getInstId());
+					
+					synchroRelatedService.updateSynchroRelated(
+							this.synchronizer,synchroRelated,UserInfo.CLASS_TYPE);
+					
+					socialsAssociate(synchroRelated,"workweixin");
 				}
 			}
 			

+ 43 - 8
maxkey-synchronizers/maxkey-synchronizer/src/main/java/org/maxkey/synchronizer/AbstractSynchronizerService.java

@@ -17,14 +17,19 @@
 
 package org.maxkey.synchronizer;
 
+import java.sql.Types;
 import java.util.HashMap;
 import java.util.List;
 
 import org.maxkey.entity.Organizations;
+import org.maxkey.entity.SocialsAssociate;
+import org.maxkey.entity.SynchroRelated;
 import org.maxkey.entity.Synchronizers;
 import org.maxkey.persistence.service.HistorySynchronizerService;
 import org.maxkey.persistence.service.OrganizationsService;
+import org.maxkey.persistence.service.SynchroRelatedService;
 import org.maxkey.persistence.service.UserInfoService;
+import org.maxkey.persistence.service.SocialsAssociatesService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -35,10 +40,12 @@ public abstract class AbstractSynchronizerService {
     
     @Autowired
     protected OrganizationsService organizationsService;
-    
     @Autowired
     protected UserInfoService userInfoService;
-    
+    @Autowired
+    protected SynchroRelatedService synchroRelatedService;
+    @Autowired
+    protected SocialsAssociatesService socialsAssociatesService;
     @Autowired
     protected HistorySynchronizerService historySynchronizerService;
     
@@ -49,20 +56,20 @@ public abstract class AbstractSynchronizerService {
     protected Organizations rootOrganization = null;
     
     
-    public HashMap<String,Organizations> loadOrgsById(String orgId) {
-        List<Organizations> orgsList = organizationsService.query(null);
-        if(orgId== null || orgId.equals("")) {
-            orgId="1";
+    public HashMap<String,Organizations> loadOrgsByInstId(String instId,String rootOrgId) {
+        List<Organizations> orgsList = organizationsService.find("instid = '" + instId + "'");
+        if(rootOrgId== null || rootOrgId.equals("")) {
+        	rootOrgId="1";
         }
         
         for(Organizations org : orgsList) {
-           if(org.getId().equals(orgId) && orgId.equals("1")) {
+           if(org.getId().equals(rootOrgId) && rootOrgId.equals("1")) {
                rootOrganization = org; 
                rootOrganization.setNamePath("/"+rootOrganization.getName());
                rootOrganization.setCodePath("/1");
                rootOrganization.setParentId("-1");
                rootOrganization.setParentName("");
-           }else if(org.getId().equals(orgId)){
+           }else if(org.getId().equals(rootOrgId)){
                rootOrganization = org; 
            }
         }
@@ -75,6 +82,26 @@ public abstract class AbstractSynchronizerService {
         return orgsNamePathMap;
     }
     
+    public void socialsAssociate(SynchroRelated synchroRelated,String provider) {
+    	SocialsAssociate socialsAssociate =
+    			socialsAssociatesService.findOne("instid = ? and userid = ? and socialuserid = ? and provider = ? ",
+    					new Object[] { 
+    							synchroRelated.getInstId(),
+    							synchroRelated.getObjectId(),
+    							synchroRelated.getOriginId(),
+    							provider 
+    					},
+    					new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,Types.VARCHAR});
+    	if(socialsAssociate == null) {
+    		socialsAssociate = new SocialsAssociate();
+    		socialsAssociate.setUserId(synchroRelated.getObjectId());
+    		socialsAssociate.setUsername(synchroRelated.getObjectName());
+    		socialsAssociate.setInstId(synchroRelated.getInstId());
+    		socialsAssociate.setProvider(provider);
+    		socialsAssociate.setSocialUserId(synchroRelated.getOriginId());
+    		socialsAssociatesService.insert(socialsAssociate);
+    	}
+    }
     public void push(HashMap<String,Organizations> orgsNamePathMap,
                      List<Organizations> orgsList,
                      Organizations parentOrg) {
@@ -141,6 +168,14 @@ public abstract class AbstractSynchronizerService {
     public void setHistorySynchronizerService(HistorySynchronizerService historySynchronizerService) {
         this.historySynchronizerService = historySynchronizerService;
     }
+
+	public SynchroRelatedService getSynchroRelatedService() {
+		return synchroRelatedService;
+	}
+
+	public void setSynchroRelatedService(SynchroRelatedService synchroRelatedService) {
+		this.synchroRelatedService = synchroRelatedService;
+	}
     
     
 }

+ 1 - 1
maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/SocialSignOnListController.java

@@ -21,10 +21,10 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.maxkey.authn.support.socialsignon.service.SocialSignOnProviderService;
-import org.maxkey.authn.support.socialsignon.service.SocialsAssociate;
 import org.maxkey.authn.support.socialsignon.service.SocialsAssociateService;
 import org.maxkey.configuration.ApplicationConfig;
 import org.maxkey.entity.Institutions;
+import org.maxkey.entity.SocialsAssociate;
 import org.maxkey.entity.SocialsProvider;
 import org.maxkey.web.WebConstants;
 import org.maxkey.web.WebContext;

+ 1 - 1
maxkey-webs/maxkey-web-mgt/src/main/resources/templates/views/orgs/orgsUpdate.ftl

@@ -3,7 +3,7 @@
 <head>
 	<#include  "../layout/header.ftl"/>
 	<#include  "../layout/common.cssjs.ftl"/>
-
+    <#setting number_format="#">
 <script type="text/javascript">
 	
 $(function () {