All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.anyline.feishu.util.FeishuUtil Maven / Gradle / Ivy

There is a newer version: 8.7.2-20241107
Show newest version
/*
 * Copyright 2006-2023 www.anyline.org
 *
 * 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.anyline.feishu.util;

import com.lark.oapi.Client;
import org.anyline.adapter.KeyAdapter;
import org.anyline.entity.DataRow;
import org.anyline.entity.DataSet;
import org.anyline.feishu.entity.Department;
import org.anyline.feishu.entity.User;
import org.anyline.net.HttpUtil;
import org.anyline.util.AnylineConfig;
import org.anyline.util.BasicUtil;
import org.anyline.util.BeanUtil;
import org.anyline.util.DateUtil;
import org.apache.http.entity.StringEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

public class FeishuUtil {
	private static final Logger log = LoggerFactory.getLogger(FeishuUtil.class); 
	private static Hashtable instances = new Hashtable(); 
	private FeishuConfig config = null;
	private Client client;
	private String tenant_access_token = null;
	private Long tenant_access_token_time = null;

	static {
		Hashtable configs = FeishuConfig.getInstances();
		for(String key:configs.keySet()){
			instances.put(key, getInstance(key));
		}
	}

	public FeishuUtil(){

	}
	public FeishuUtil(FeishuConfig config){
		this.config = config;
		client = Client.newBuilder(config.APP_ID, config.APP_SECRET).build();
	}
	public static Hashtable getInstances(){
		return instances;
	}
	public Client client(){
		return client;
	}
	public void client(Client client){
		this.client = client;
	}

	public static FeishuUtil getInstance(){
		return getInstance(FeishuConfig.DEFAULT_INSTANCE_KEY);
	} 
	public static FeishuUtil getInstance(String key){
		if(BasicUtil.isEmpty(key)){
			key = FeishuConfig.DEFAULT_INSTANCE_KEY;
		} 
		FeishuUtil util = instances.get(key); 
		if(null == util){
			FeishuConfig config = FeishuConfig.getInstance(key);
			if(null != config) {
				util = new FeishuUtil(config);
				instances.put(key, util);
			}
		}
		return util; 
	}
	public static FeishuUtil reg(String key, DataRow config){
		FeishuConfig conf = FeishuConfig.register(key, config);
		FeishuUtil util = new FeishuUtil(conf);
		instances.put(key, util);
		return util;
	}
	public static FeishuUtil reg(String key, String id, String secret){
		FeishuConfig conf = FeishuConfig.register(key, id, secret);
		FeishuUtil util = new FeishuUtil(conf);
		instances.put(key, util);
		return util;
	}
	public static FeishuUtil reg(String key, String id, String secret, String redirect){
		FeishuConfig conf = FeishuConfig.register(key, id, secret, redirect);
		FeishuUtil util = new FeishuUtil(conf);
		instances.put(key, util);
		return util;
	}
	public FeishuConfig config(){
		return config;
	}
	public String tenant_access_token(){
		if(null == tenant_access_token || (System.currentTimeMillis()-tenant_access_token_time)/1000 >7000){
			flushToken();
		}
		return tenant_access_token;
	}

	/**
	 *
	 * @param code 用户授权确认后重定向中的code
	 * @return DataRow
	 */
	public DataRow access_token(String code){
		DataRow token = null;
		String url = "https://open.feishu.cn/open-apis/authen/v1/oidc/access_token";
		Map header = new Hashtable<>();
		header.put("Content-Type","application/json; charset=utf-8");
		header.put("Authorization", "Bearer " + tenant_access_token());
		Map params = new HashMap<>();
		params.put("grant_type", "authorization_code");
		params.put("code", code);
		String json = BeanUtil.map2json(params);
		String body = HttpUtil.post(header, url, new StringEntity(json, "UTF-8")).getText();
		log.info("[get feishu access token][body:{}]", body);
		DataRow row = DataRow.parseJson(KeyAdapter.KEY_CASE.SRC, body);
		token = row.getRow("data");
		return token;
	}
	public User user(String code){
		User user = user(access_token(code));
		return user;
	}
	public User user(DataRow token){
		User user = new User();
		String url = "https://open.feishu.cn/open-apis/authen/v1/user_info";
		Map header = new Hashtable<>();
		header.put("Content-Type","application/json; charset=utf-8");
		header.put("Authorization", "Bearer " + token.getString("access_token"));
		String body = HttpUtil.get(header, url).getText();
		log.info("[get feishu user info][body:{}]", body);
		DataRow row = DataRow.parseJson(KeyAdapter.KEY_CASE.SRC, body);
		DataRow data = row.getRow("data");
		user = info(data);
		return user;
	}
	public static User info(DataRow data){
		User user = new User();
		user.setName(data.getString("name"));
		user.setEnName(data.getString("en_name"));
		if(data.isNotEmpty("avatar")){
			//批量获取用户列表
			DataRow avators = data.getRow("avatar");
			if(null != avators){
				user.setAvatarBig(data.getString("AVATAR_640"));
				user.setAvatarUrl(data.getString("AVATAR_ORIGIN"));
				user.setAvatarThumb(data.getString("AVATAR_72"));
				user.setAvatarMiddle(data.getString("AVATAR_240"));
			}
		}else {
			//用户登录获取信息
			user.setAvatarBig(data.getString("avatar_big"));
			user.setAvatarUrl(data.getString("avatar_url"));
			user.setAvatarThumb(data.getString("avatar_thumb"));
			user.setAvatarMiddle(data.getString("avatar_middle"));
		}
		if(data.isNotEmpty("status")){
			DataRow status = data.getRow("status");
			if(null != status){
				user.setActivateStatus(status.getBoolean("is_activated", null));	//激活
				user.setFrozenStatus(status.getBoolean("is_frozen", null));		//冻结
				user.setResignStatus(status.getBoolean("is_resigned", null));		//离职
			}
		}
		Long joinTime = data.getLong("join_time", 0);
		if(joinTime > 0){
			Date date = DateUtil.parse(joinTime*1000);
			user.setJoinTime(date);
			user.setJoinYmd(DateUtil.format(date, "yyyy-MM-dd"));
		}
		user.setNickname(data.getString("nickname"));
		List depts = (List)data.getList("department_ids");
		user.setDepartmentIds(depts);
		user.setLeaderId(data.getString("leader_user_id"));
		user.setJobTitle(data.getString("job_title"));
		user.setWorkStation(data.getString("work_station"));
		user.setOpenid(data.getString("open_id"));
		user.setUnionid(data.getString("union_id"));
		user.setEmail(data.getString("email"));
		user.setMobile(data.getString("mobile"));
		user.setEnterpriseEmail(data.getString("enterprise_email"));
		user.setEmployeeNo(data.getString("employee_no"));
		user.setId(data.getString("user_id"));
		user.setTenantKey(data.getString("tenant_key"));
		return user;
	}

	/**
	 * 所有可访问用户
	 * @return List
	 */
	public List users(){
		List users = new ArrayList<>();
		String url ="https://open.feishu.cn/open-apis/contact/v3/scopes";
		Map header = new HashMap<>();
		header.put("Authorization", "Bearer " + tenant_access_token());
		String body = HttpUtil.get(header, url).getText();
		DataRow row = DataRow.parseJson(body);
		List ids = (List)row.getRow("data").getList("user_ids");
		if(null != ids) {
			List> pages = BeanUtil.page(ids, 50);
			for (List page : pages) {
				users.addAll(users(page));
			}
		}
		return users;
	}
	public List users(List ids){
		List users = new ArrayList<>();
		Map header = new HashMap<>();
		header.put("Authorization", "Bearer " + tenant_access_token());
		Map params = new HashMap<>();
		params.put("user_ids", ids);
		String url = "https://open.feishu.cn/open-apis/contact/v3/users/batch";
		String body = HttpUtil.get(header, url, "UTF-8", params).getText();
		DataRow row = DataRow.parseJson(body);
		DataSet items = row.getRow("data").getSet("items");
		if(null != items) {
			for (DataRow item : items) {
				users.add(info(item));
			}
		}
		return users;
	}
	public List users(Department department){
		List users = new ArrayList<>();
		Map header = new HashMap<>();
		header.put("Authorization", "Bearer " + tenant_access_token());
		Map params = new HashMap<>();
		params.put("department_id", "0");
		params.put("page_size", 50);
		if(null != department){
			String id = department.getCode();
			String openid = department.getOpenid();
			if(BasicUtil.isNotEmpty(id)){
				params.put("department_id_type", "department_id");
				params.put("department_id", id);
			}else if(BasicUtil.isNotEmpty(openid)){
				params.put("department_id_type", "open_department_id");
				params.put("department_id", openid);
			}
		}
		String url = "https://open.feishu.cn/open-apis/contact/v3/users/find_by_department";
		while (true) {
			String body = HttpUtil.get(header, url, "UTF-8", params).getText();
			DataRow row = DataRow.parseJson(body);
			DataRow data = row.getRow("data");
			if(null != data) {
				DataSet items = data.getSet("items");
				if (null != items) {
					for (DataRow item : items) {
						users.add(info(item));
					}
				}
				params.put("page_token", data.getString("page_token"));
				if(!data.getBoolean("has_more", false)){
					break;
				}
			}else{
				break;
			}
		}
		return users;
	}
	public List departments() {
		return departments("0");
	}
	/**
	 * 所有可访问部门
	 * @return List
	 */
	public List departments(String parent) {
		List departments = new ArrayList<>();
		String url = "https://open.feishu.cn/open-apis/contact/v3/departments/"+parent+"/children";
		Map header = new HashMap<>();
		header.put("Authorization", "Bearer " + tenant_access_token());
		Map params = new HashMap<>();
		params.put("page_size", 50);
		while (true) {
			String body = HttpUtil.get(header, url, "UTF-8", params).getText();
			DataRow row = DataRow.parseJson(body);
			if (row.getInt("CODE", -1) == 0) {
				DataRow data = row.getRow("data");
				if(null != data) {
					DataSet items = data.getItems();
					if (null != items) {
						for (DataRow item : items) {
							Department department = new Department();
							department.setCode(item.getString("department_id"));
							department.setName(item.getString("name"));
							department.setOpenid(item.getString("open_department_id"));
							department.setParentCode(item.getString("parent_department_id"));
							DataSet leaders = item.getSet("leaders");
							if (null != leaders) {
								for (DataRow leader : leaders) {
									if (leader.getInt("leaderType", 0) == 1) {//主负责人
										department.setLeaderCode(leader.getString("leaderID"));
									}
								}
							}
							departments.add(department);
						}
					}
					if(!data.getBoolean("has_more")){
						break;
					}
					params.put("page_token", data.getString("page_token"));
				}else{
					break;
				}
			} else {
				log.warn("[departments][response:{}]", body);
				break;
			}
		}
		return departments;
	}


	private void flushToken(){
		String url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal/";
		Map header = new Hashtable<>();
		header.put("Content-Type","application/json; charset=utf-8");
		Map params = new HashMap<>();
		params.put("app_id", config.APP_ID);
		params.put("app_secret", config.APP_SECRET);
		try {
			String json = BeanUtil.map2json(params);
			String body = HttpUtil.post(header, url, new StringEntity(json, "UTF-8")).getText();
			DataRow row = DataRow.parseJson(body);
			if("0".equals(row.getString("code"))){
				tenant_access_token = row.getString("tenant_access_token");
				tenant_access_token_time = System.currentTimeMillis();
			}else {
				log.warn("[flush token][response:{}]", body);
			}
		}catch (Exception e){
			e.printStackTrace();
		}
	}

	/**
	 * 创建用户登录连接
	 * @param callback 回调地址(可以从url获取access_token)
	 * @param scope scope
	 * @param state state
	 * @return String
	 */
	public String createAuthUrl(String callback, String scope, String state){
		StringBuilder builder = new StringBuilder();
		//https://open.feishu.cn/open-apis/authen/v1/authorize?app_id=cli_a69b4944f47b100e&redirect_uri=https%3A%2F%2Ffs.deepbit.cn&scope=contact:contact%20bitable:app:readonly&state=213
		builder.append("https://open.feishu.cn/open-apis/authen/v1/authorize?app_id=").append(config.APP_ID);
		if(BasicUtil.isEmpty(callback)){
			callback = config.OAUTH_REDIRECT_URL;
		}
		builder.append("&redirect_uri=").append(HttpUtil.encode(callback, false, true));
		//参考https://open.feishu.cn/document/server-docs/application-scope/scope-list
		builder.append("&scope=").append(scope);
		if(BasicUtil.isNotEmpty(state)) {
			builder.append("&state=").append(state);
		}
		return builder.toString();
	}
	public String createAuthUrl(String callback, String state){
		return createAuthUrl(callback, "contact:contact.base:readonly", state);
	}
	public String createAuthUrl(String state){
		return createAuthUrl(config.OAUTH_REDIRECT_URL, state);
	}
} 




© 2015 - 2024 Weber Informatics LLC | Privacy Policy