user-center-wecom/company.go (214 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 wecom import ( "encoding/json" "fmt" "strings" "github.com/go-resty/resty/v2" "github.com/segmentfault/pacman/log" "github.com/silenceper/wechat/v2/cache" "github.com/silenceper/wechat/v2/work" workConfig "github.com/silenceper/wechat/v2/work/config" "github.com/tidwall/gjson" ) type Company struct { CorpID string CorpSecret string AgentID string CallbackURL string Work *work.Work DepartmentMapping map[int]*Department EmployeeMapping map[string]*Employee UserDetailInfoMapping map[string]*UserDetailInfo } func NewCompany(corpID, corpSecret, agentID string) *Company { memory := cache.NewMemory() cfg := &workConfig.Config{ CorpID: corpID, CorpSecret: corpSecret, AgentID: agentID, Cache: memory, } newWork := work.NewWork(cfg) return &Company{ CorpID: corpID, CorpSecret: corpSecret, AgentID: agentID, Work: newWork, DepartmentMapping: make(map[int]*Department), EmployeeMapping: make(map[string]*Employee), UserDetailInfoMapping: make(map[string]*UserDetailInfo), } } func (c *Company) ListDepartmentAll() (err error) { log.Debugf("try to list department all") token, err := c.Work.GetOauth().GetAccessToken() if err != nil { return fmt.Errorf("get access token failed: %w", err) } log.Debugf("get access token success") resp, err := resty.New().R().Get("https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=" + token) if err != nil { return fmt.Errorf("get department list failed: %w", err) } if resp.StatusCode() != 200 { return fmt.Errorf("get department list failed: %s", resp.String()) } log.Debugf("get department success: %s", resp.String()) department := gjson.Get(resp.String(), "department").String() var departments []*Department err = json.Unmarshal([]byte(department), &departments) if err != nil { return fmt.Errorf("unmarshal department failed: %w", err) } departmentMapping := make(map[int]*Department) for _, d := range departments { departmentMapping[d.Id] = d } c.DepartmentMapping = departmentMapping log.Debugf("get department list: %d", len(departments)) return nil } func (c *Company) ListUser() (err error) { token, err := c.Work.GetOauth().GetAccessToken() if err != nil { return fmt.Errorf("get access token failed: %w", err) } log.Debugf("get access token success") for _, department := range c.DepartmentMapping { log.Debugf("try to get department user list: %d %s", department.Id, department.Name) resp, err := resty.New().R().Get(fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=%d&access_token=%s", department.Id, token)) if err != nil { log.Errorf("get department user list failed: %v", err) continue } if gjson.Get(resp.String(), "errcode").Int() != 0 { log.Errorf("get department user list failed: %v", resp.String()) continue } userList := gjson.Get(resp.String(), "userlist").String() var employees []*Employee err = json.Unmarshal([]byte(userList), &employees) if err != nil { log.Errorf("unmarshal userList failed: %w", err) continue } log.Debugf("get department user list: %d", len(employees)) for _, employee := range employees { c.EmployeeMapping[employee.Userid] = employee log.Debugf(employee.Userid) } } log.Debugf("all user amount: %d", len(c.EmployeeMapping)) return nil } func (c *Company) AuthUser(code string) (info *UserInfo, err error) { token, err := c.Work.GetOauth().GetAccessToken() if err != nil { return nil, fmt.Errorf("get access token failed: %w", err) } getUserInfoResp, err := resty.New().R().Get(fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=" + token + "&code=" + code)) if err != nil { log.Errorf("get user info failed: %v", err) return nil, err } log.Debugf("get user info: %s", getUserInfoResp.String()) userTicket := gjson.Get(getUserInfoResp.String(), "user_ticket").String() getUserDetailResp, err := resty.New().R(). SetHeader("Content-Type", "application/json"). SetBody(map[string]string{"user_ticket": userTicket}). Post(fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail?access_token=" + token)) if err != nil { log.Errorf("get user info failed: %v", err) return nil, err } var userInfoResp *AuthUserInfoResp err = json.Unmarshal([]byte(getUserDetailResp.String()), &userInfoResp) if err != nil { log.Errorf("unmarshal user info failed: %s", err) return nil, err } if userInfoResp.Errcode != 0 { log.Errorf("get user info failed: %v", getUserDetailResp.String()) return nil, fmt.Errorf("get user info failed") } log.Debugf("get user info: %s", getUserDetailResp.String()) employee := c.EmployeeMapping[userInfoResp.Userid] if employee == nil { return nil, fmt.Errorf("user %s not found in employee list", userInfoResp.Userid) } userDetailInfo, err := c.GetUserDetailInfo(userInfoResp.Userid) if err != nil { return nil, err } userInfo := &UserInfo{ Userid: userInfoResp.Userid, Mobile: userInfoResp.Mobile, Gender: userInfoResp.Gender, Email: userInfoResp.Email, Avatar: userInfoResp.Avatar, QrCode: userInfoResp.QrCode, Address: userInfoResp.Address, Name: employee.Name, Position: userDetailInfo.Position, IsAvailable: userDetailInfo.Status == 1, DepartmentIDs: employee.Department, } return userInfo, nil } func (c *Company) GetRedirectURL(callbackURl string) (redirectURL string) { return c.Work.GetOauth().GetTargetPrivateURL(callbackURl, c.AgentID) } func (c *Company) GetUserDetailInfo(userid string) (info *UserDetailInfo, err error) { token, err := c.Work.GetOauth().GetAccessToken() if err != nil { return nil, fmt.Errorf("get access token failed: %w", err) } userDetailInfoResp, err := resty.New().R().Get(fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=" + token + "&userid=" + userid)) if err != nil { log.Errorf("get user info failed: %v", err) return nil, err } var userDetailInfo *UserDetailInfo _ = json.Unmarshal([]byte(userDetailInfoResp.String()), &userDetailInfo) if userDetailInfo.Errcode != 0 { log.Errorf("get user info failed: %v", userDetailInfoResp.String()) return nil, fmt.Errorf("get user info failed") } log.Debugf("get user detail info: %s", userDetailInfoResp.String()) c.UserDetailInfoMapping[userid] = userDetailInfo return userDetailInfo, nil } func (c *Company) formatDepartmentAndPosition(departmentIDs []int, position string) string { var departmentName []string for _, t := range departmentIDs { name := c.fullDepartmentName(t) if len(name) == 0 { continue } departmentName = append(departmentName, name) } var desc []string if dep := strings.Join(departmentName, ","); len(dep) > 0 { desc = append(desc, fmt.Sprintf("部门:%s", dep)) } if len(position) > 0 { desc = append(desc, fmt.Sprintf("职位:%s", position)) } return strings.Join(desc, "\n") } func (c *Company) fullDepartmentName(departmentID int) string { departmentNames := make([]string, 0) for { department := c.DepartmentMapping[departmentID] if department == nil { break } departmentNames = append([]string{department.Name}, departmentNames...) if department.ParentID == 0 { break } departmentID = department.ParentID } return strings.Join(departmentNames, "/") }