新增修改医生

This commit is contained in:
wucongxing 2023-07-07 17:58:38 +08:00
parent a38fe237dd
commit e027c03950
17 changed files with 1345 additions and 41 deletions

View File

@ -115,7 +115,7 @@ func (r *UserDoctor) PutUserDoctor(c *gin.Context) {
userDoctorService := service.UserDoctorService{}
_, err = userDoctorService.PutUserDoctor(doctorId, userDoctorRequest.PutUserDoctor)
if err != nil {
responses.FailWithMessage("修改失败", c)
responses.FailWithMessage(err.Error(), c)
return
}

View File

@ -98,3 +98,12 @@ func (r *AdminMenuDao) GetAdminMenuId() (m []int64, err error) {
}
return m, nil
}
// GetAdminMenuListByIdWithIn 获取全部正常菜单列表-in
func (r *AdminMenuDao) GetAdminMenuListByIdWithIn(menuIds []int64) (m []*model.AdminMenu, err error) {
err = global.Db.Where("menu_id in ?", menuIds).Where("menu_status = ?", 1).Order("order_num asc").Find(&m).Error
if err != nil {
return nil, err
}
return m, nil
}

101
api/dao/user.go Normal file
View File

@ -0,0 +1,101 @@
package dao
import (
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hospital-admin-api/api/model"
"hospital-admin-api/api/requests"
"hospital-admin-api/global"
)
type UserDao struct {
}
// GetUserById 获取用户数据-用户id
func (r *UserDao) GetUserById(userId int64) (m *model.User, err error) {
err = global.Db.First(&m, userId).Error
if err != nil {
return nil, err
}
return m, nil
}
// GetUserPreloadById 获取用户数据-加载全部关联-用户id
func (r *UserDao) GetUserPreloadById(userId int64) (m *model.User, err error) {
err = global.Db.Preload(clause.Associations).First(&m, userId).Error
if err != nil {
return nil, err
}
return m, nil
}
// DeleteUser 删除用户
func (r *UserDao) DeleteUser(tx *gorm.DB, maps interface{}) error {
err := tx.Where(maps).Delete(&model.User{}).Error
if err != nil {
return err
}
return nil
}
// DeleteUserById 删除用户-用户id
func (r *UserDao) DeleteUserById(tx *gorm.DB, userId int64) error {
if err := tx.Delete(&model.User{}, userId).Error; err != nil {
return err
}
return nil
}
// EditUser 修改用户
func (r *UserDao) EditUser(tx *gorm.DB, maps interface{}, data interface{}) error {
err := tx.Model(&model.User{}).Where(maps).Updates(data).Error
if err != nil {
return err
}
return nil
}
// EditUserById 修改用户-用户id
func (r *UserDao) EditUserById(tx *gorm.DB, userId int64, data interface{}) error {
err := tx.Model(&model.User{}).Where("user_id = ?", userId).Updates(data).Error
if err != nil {
return err
}
return nil
}
// GetUserList 获取用户列表
func (r *UserDao) GetUserList(maps interface{}) (m []*model.User, err error) {
err = global.Db.Where(maps).Find(&m).Error
if err != nil {
return nil, err
}
return m, nil
}
// GetUserDaoPageSearch 获取用户列表-分页
func (r *UserDao) GetUserDaoPageSearch(getUserPage requests.GetUserPage, page, pageSize int) (m []*model.User, total int64, err error) {
var totalRecords int64
// 构建查询条件
query := global.Db.Model(&model.User{})
// 查询总数量
if err := query.Count(&totalRecords).Error; err != nil {
return nil, 0, err
}
err = query.Scopes(model.Paginate(page, pageSize)).Find(&m).Error
if err != nil {
return nil, 0, err
}
return m, totalRecords, nil
}
// AddUser 新增用户
func (r *UserDao) AddUser(tx *gorm.DB, model *model.User) (*model.User, error) {
if err := tx.Create(model).Error; err != nil {
return nil, err
}
return model, nil
}

71
api/dao/userCaCert.go Normal file
View File

@ -0,0 +1,71 @@
package dao
import (
"gorm.io/gorm"
"hospital-admin-api/api/model"
"hospital-admin-api/global"
)
type UserCaCert struct {
}
// GetUserCaCertById 获取监管证书数据-监管证书id
func (r *UserCaCert) GetUserCaCertById(certId int64) (m *model.UserCaCert, err error) {
err = global.Db.First(&m, certId).Error
if err != nil {
return nil, err
}
return m, nil
}
// GetUserCaCertByUserId 获取监管证书数据-监管证书id
func (r *UserCaCert) GetUserCaCertByUserId(userId int64) (m *model.UserCaCert, err error) {
err = global.Db.Where("user_id = ?", userId).First(&m).Error
if err != nil {
return nil, err
}
return m, nil
}
// GetUserCaCertListByUserId 获取监管证书数据-监管证书id
func (r *UserCaCert) GetUserCaCertListByUserId(userId int64) (m []*model.UserCaCert, err error) {
err = global.Db.Where("user_id = ?", userId).Find(&m).Error
if err != nil {
return nil, err
}
return m, nil
}
// AddUserCaCert 新增监管证书
func (r *UserCaCert) AddUserCaCert(tx *gorm.DB, model *model.UserCaCert) (*model.UserCaCert, error) {
if err := tx.Create(model).Error; err != nil {
return nil, err
}
return model, nil
}
// GetUserCaCertList 获取监管证书列表
func (r *UserCaCert) GetUserCaCertList(maps interface{}) (m []*model.UserCaCert, err error) {
err = global.Db.Where(maps).Find(&m).Error
if err != nil {
return nil, err
}
return m, nil
}
// DeleteUserCaCertById 删除监管证书-监管证书id
func (r *UserCaCert) DeleteUserCaCertById(tx *gorm.DB, certId int64) error {
if err := tx.Delete(&model.UserCaCert{}, certId).Error; err != nil {
return err
}
return nil
}
// EditUserCaCertById 修改监管证书-监管证书id
func (r *UserCaCert) EditUserCaCertById(tx *gorm.DB, certId int64, data interface{}) error {
err := tx.Model(&model.UserCaCert{}).Where("cert_id = ?", certId).Updates(data).Error
if err != nil {
return err
}
return nil
}

20
api/model/userCaCert.go Normal file
View File

@ -0,0 +1,20 @@
package model
// UserCaCert 医师/药师ca监管证书表
type UserCaCert struct {
CertId int64 `gorm:"column:cert_id;type:bigint(19);primary_key;comment:主键id" json:"cert_id"`
UserId int64 `gorm:"column:user_id;type:bigint(19);comment:用户id(系统证书时为null)" json:"user_id"`
IsSystem int `gorm:"column:is_system;type:tinyint(1);default:0;comment:是否系统证书0:否 1:是)" json:"is_system"`
Type int `gorm:"column:type;type:tinyint(1);comment:证书类型1:线下 2:线上)" json:"type"`
CertBase64 string `gorm:"column:cert_base64;type:text;comment:签名值证书" json:"cert_base64"`
CertChainP7 string `gorm:"column:cert_chain_p7;type:text;comment:证书链" json:"cert_chain_p7"`
CertSerialNumber string `gorm:"column:cert_serial_number;type:varchar(100);comment:证书序列号" json:"cert_serial_number"`
CaPin string `gorm:"column:ca_pin;type:varchar(100);comment:ca认证pin值" json:"ca_pin"`
IsSignConfig int `gorm:"column:is_sign_config;type:tinyint(1);default:0;comment:是否已添加签章配置(第一次需申请)" json:"is_sign_config"`
SignConfig string `gorm:"column:sign_config;type:text;comment:签章坐标配置" json:"sign_config"`
Model
}
func (m *UserCaCert) TableName() string {
return "gdxz_user_ca_cert"
}

View File

@ -16,28 +16,29 @@ type RoleService struct{}
// GetRoleMenuList 获取角色菜单
func (r *RoleService) GetRoleMenuList(roleId int64, isAdmin bool) ([]*roleResponse.GetRoleMenuList, error) {
// 获取角色菜单
AdminRoleMenuDao := dao.AdminRoleMenuDao{}
AdminMenuDao := dao.AdminMenuDao{}
adminRoleMenuDao := dao.AdminRoleMenuDao{}
adminMenuDao := dao.AdminMenuDao{}
var menuIDs []int64
var err error
if isAdmin {
// 超级管理员
menuIDs, err = AdminMenuDao.GetAdminMenuId()
menuIDs, err = adminMenuDao.GetAdminMenuId()
if err != nil {
return []*roleResponse.GetRoleMenuList{}, nil
return nil, nil
}
} else {
menuIDs, err = AdminRoleMenuDao.GetAdminRoleMenuIdByRoleId(roleId)
// 普通用户
menuIDs, err = adminRoleMenuDao.GetAdminRoleMenuIdByRoleId(roleId)
if err != nil {
return []*roleResponse.GetRoleMenuList{}, nil
return nil, nil
}
}
// 获取全部正常非按钮菜单列表
adminMenu, _ := AdminMenuDao.GetAdminMenuListNonButtonNormalSortOrderNum()
adminMenu, _ := adminMenuDao.GetAdminMenuListNonButtonNormalSortOrderNum()
if adminMenu == nil {
return []*roleResponse.GetRoleMenuList{}, nil
return nil, nil
}
var getRoleMenuListResponse []*roleResponse.GetRoleMenuList

View File

@ -5,6 +5,8 @@ import (
"hospital-admin-api/api/dao"
"hospital-admin-api/api/requests"
"hospital-admin-api/config"
"hospital-admin-api/extend/ca"
"hospital-admin-api/extend/tencentIm"
"hospital-admin-api/global"
"strconv"
"strings"
@ -15,6 +17,7 @@ type UserDoctorService struct {
// PutUserDoctor 修改医生
func (r *UserDoctorService) PutUserDoctor(doctorId int64, userDoctorRequest requests.PutUserDoctor) (bool, error) {
// 获取医生数据
userDoctorDao := dao.UserDoctorDao{}
userDoctor, err := userDoctorDao.GetUserDoctorById(doctorId)
@ -29,17 +32,22 @@ func (r *UserDoctorService) PutUserDoctor(doctorId int64, userDoctorRequest requ
return false, errors.New("医生详情数据错误")
}
// 医生数据
userDoctorData := make(map[string]interface{})
// 获取用户数据
userDao := dao.UserDao{}
user, err := userDao.GetUserById(userDoctor.UserId)
if err != nil {
return false, errors.New("医生数据错误")
}
// 医生详情数据
userDoctorInfoData := make(map[string]interface{})
userDoctorData := make(map[string]interface{}) // 医生数据
userDoctorInfoData := make(map[string]interface{}) // 医生详情数据
userData := make(map[string]interface{}) // 用户数据
// 处理头像
userDoctorRequest.Avatar = strings.Replace(userDoctorRequest.Avatar, config.C.Oss.OssCustomDomainName, "", 1)
if userDoctor.Avatar != userDoctorRequest.Avatar {
userDoctorData["avatar"] = userDoctorRequest.Avatar
userDoctorInfoData["avatar"] = userDoctorRequest.Avatar
avatar := strings.Replace(userDoctorRequest.Avatar, config.C.Oss.OssCustomDomainName, "", 1)
if userDoctor.Avatar != avatar {
userDoctorData["avatar"] = avatar
userData["avatar"] = avatar
}
// 处理职称
@ -53,6 +61,9 @@ func (r *UserDoctorService) PutUserDoctor(doctorId int64, userDoctorRequest requ
return false, errors.New("科室错误")
}
if departmentCustomId == 0 && userDoctor.DepartmentCustomId != 0 {
return false, errors.New("未选择新的科室")
}
if userDoctor.DepartmentCustomId != departmentCustomId || userDoctor.DepartmentCustomName != userDoctorRequest.DepartmentCustomName {
// 获取科室数据
hospitalDepartmentCustomDao := dao.HospitalDepartmentCustom{}
@ -237,25 +248,132 @@ func (r *UserDoctorService) PutUserDoctor(doctorId int64, userDoctorRequest requ
}
}
// 判断头像是否修改同步修改im
// 判断科室是否修改同步修改ca平台
// 判断签名图片是否修改同步修改ca平台
// 修改医生数据
if len(userDoctorData) != 0 {
err = userDao.EditUserById(tx, userDoctor.UserId, userData)
if err != nil {
tx.Rollback()
return false, errors.New("修改失败")
}
}
// _, ok := userDoctorData["department_custom_id"]
// if ok {
// // 变更科室
//
// }
//
// paramMap := map[string]string{
// "userName": "zj",
// "age": "19",
// }
//
// sign := ca.GenerateSignature(paramMap)
// fmt.Println(sign)
// 判断头像是否修改同步修改im
if userDoctor.Avatar != avatar {
profileItem := []tencentIm.ProfileItem{
{
Tag: "Tag_Profile_IM_Image",
Value: userDoctorRequest.Avatar,
},
}
res, err := tencentIm.SetProfile(strconv.FormatInt(userDoctor.UserId, 10), profileItem)
if err != nil || res != true {
tx.Rollback()
return false, errors.New("头像设置失败")
}
}
// 判断科室是否修改同步修改ca平台
if userDoctor.DepartmentCustomId != departmentCustomId {
// 获取科室数据
hospitalDepartmentCustomDao := dao.HospitalDepartmentCustom{}
hospitalDepartmentCustom, err := hospitalDepartmentCustomDao.GetHospitalDepartmentCustomById(departmentCustomId)
if err != nil || hospitalDepartmentCustom == nil {
tx.Rollback()
return false, errors.New("科室错误")
}
// 获取云证书数据
userCaCertDao := dao.UserCaCert{}
userCaCerts, err := userCaCertDao.GetUserCaCertListByUserId(userDoctor.UserId)
if err != nil {
tx.Rollback()
return false, errors.New("修改失败")
}
if userCaCerts != nil && len(userCaCerts) > 0 {
// 修改云证书
editCloudCertRequestData := &ca.EditCloudCertRequestData{
EntityId: strconv.FormatInt(userDoctor.UserId, 10),
EntityType: "Personal",
PersonalPhone: user.Mobile,
PersonalName: userDoctorInfo.CardName,
PersonalIdNumber: userDoctorInfo.CardNum,
OrgName: "",
OrgNumber: "",
Pin: strconv.FormatInt(userDoctor.UserId, 10),
OrgDept: hospitalDepartmentCustom.DepartmentName, // // 卫生证书:医院部门
Province: "四川省",
Locality: "成都市",
AuthType: "实人认证",
// AuthTime: strconv.FormatInt(time.Now().Unix(), 10),
AuthTime: "1688694270",
AuthResult: "认证通过",
AuthNoticeType: "数字证书变更告知",
}
editCloudCertResponse, err := ca.EditCloudCert(editCloudCertRequestData)
if err != nil || editCloudCertResponse == nil {
tx.Rollback()
return false, errors.New(err.Error())
}
// 修改ca监管证书表
userCaCertDao := dao.UserCaCert{}
data := make(map[string]interface{})
data["cert_base64"] = editCloudCertResponse.CertBase64
data["cert_chain_p7"] = editCloudCertResponse.CertP7
data["cert_serial_number"] = editCloudCertResponse.CertP7
err = userCaCertDao.EditUserCaCertById(tx, userCaCerts[0].CertId, data)
if err != nil {
tx.Rollback()
return false, errors.New("删除失败")
}
}
}
// 判断签名图片是否修改同步修改ca平台
// 1、新用户未存在证书
if userDoctorRequest.SignImage != "" {
signImage := strings.Replace(userDoctorRequest.SignImage, "https://img.applets.igandanyiyuan.com", "", 1)
if signImage != userDoctorInfo.SignImage {
// 检测是否存在云证书
userCaCertDao := dao.UserCaCert{}
userCaCerts, err := userCaCertDao.GetUserCaCertListByUserId(userDoctor.UserId)
if err != nil {
tx.Rollback()
return false, errors.New("修改失败")
}
if userCaCerts != nil && len(userCaCerts) > 0 {
userCaCert := userCaCerts[0]
// 检测是否已经添加签章配置
if userCaCert.IsSignConfig == 1 {
// 修改签章配置为未添加
data := make(map[string]interface{})
data["is_sign_config"] = 0
err = userCaCertDao.EditUserCaCertById(tx, userCaCert.CertId, data)
if err != nil {
tx.Rollback()
return false, errors.New(err.Error())
}
// 删除签章配置
deleteUserSignConfigRequestData := &ca.DeleteUserSignConfigRequestData{
UserId: strconv.FormatInt(userDoctor.UserId, 10),
ConfigKey: strconv.FormatInt(userDoctor.UserId, 10),
}
_, err := ca.DeleteUserSignConfig(deleteUserSignConfigRequestData)
if err != nil {
tx.Rollback()
return false, errors.New(err.Error())
}
}
}
}
}
tx.Commit()
return true, nil
//
}

View File

@ -44,4 +44,11 @@ oss:
ca-online:
ca-online-app-id: SCCA1646691325903052802
ca-online-app-secret: adf718ebc1fb4bb7b158de9117d1313a
ca-online-api-url: http://testmicrosrv.scca.com.cn:9527
ca-online-api-url: http://testmicrosrv.scca.com.cn:9527
# [腾讯im]
im:
im-app-id: 1400798221
im-secret: fc45ab469ca632a700166973d87b3a6f56a855cb92d7cffb54e4d37135c097da
im-base-url: https://console.tim.qq.com/
im-token: NDc5MzExMDMxMDY2NDMxNDg5L

View File

@ -11,5 +11,6 @@ type Config struct {
Jwt Jwt `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
Oss Oss `mapstructure:"oss" json:"oss" yaml:"oss"`
Snowflake int64 `mapstructure:"snowflake" json:"snowflake" yaml:"snowflake"`
CaOnline CaOnline `mapstructure:"ca_online" json:"ca_online" yaml:"ca_online"`
CaOnline CaOnline `mapstructure:"ca-online" json:"ca-online" yaml:"ca-online"`
Im Im `mapstructure:"im" json:"im" yaml:"im"`
}

8
config/im.go Normal file
View File

@ -0,0 +1,8 @@
package config
type Im struct {
ImAppID int `mapstructure:"im-app-id" json:"im-app-id" yaml:"im-app-id"`
ImSecret string `mapstructure:"im-secret" json:"im-secret" yaml:"im-secret"`
ImBaseUrl string `mapstructure:"im-base-url" json:"im-base-url" yaml:"im-base-url"`
ImToken string `mapstructure:"im-token" json:"im-token" yaml:"im-token"`
}

View File

@ -4,13 +4,25 @@ import (
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"errors"
"hospital-admin-api/config"
"io"
"net/http"
"net/url"
"sort"
"strings"
)
type Response struct {
ResultCode int `json:"result_code"`
ResultMsg string `json:"result_msg"`
Body interface{} `json:"body"`
Success bool `json:"success"`
}
// GenerateSignature 生成签名
func GenerateSignature(paramMap map[string]string) string {
func GenerateSignature(paramMap map[string]interface{}) string {
keys := make([]string, 0, len(paramMap))
for k := range paramMap {
if k == "pdfFile" {
@ -22,7 +34,10 @@ func GenerateSignature(paramMap map[string]string) string {
var toSign string
for _, k := range keys {
v := paramMap[k]
v, ok := paramMap[k].(string)
if !ok {
return ""
}
toSign += v + "&"
}
toSign = strings.TrimSuffix(toSign, "&")
@ -34,3 +49,66 @@ func GenerateSignature(paramMap map[string]string) string {
return signature
}
// 统一请求
func postRequest(requestUrl string, formData url.Values, signature string) (map[string]interface{}, error) {
payload := strings.NewReader(formData.Encode())
// 创建 POST 请求
req, err := http.NewRequest("POST", requestUrl, payload)
if err != nil {
return nil, err
}
// 设置请求头
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("app_id", config.C.CaOnline.CaOnlineAppId)
req.Header.Add("signature", signature)
// 创建 HTTP 请求客户端
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer func(Body io.ReadCloser) {
_ = Body.Close()
}(resp.Body)
if resp.StatusCode != 200 {
return nil, errors.New("请求失败")
}
// 读取响应内容
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var response Response
err = json.Unmarshal([]byte(respBody), &response)
if err != nil {
// json解析失败
return nil, err
}
if response.ResultCode != 0 {
if response.ResultMsg != "" {
return nil, errors.New(response.ResultMsg)
} else {
return nil, errors.New("请求ca失败")
}
}
body := make(map[string]interface{})
if response.Body != nil || response.Body != "" {
bodyMap, ok := response.Body.(map[string]interface{})
if !ok {
body = bodyMap
}
}
if len(body) == 0 {
return nil, nil
}
return body, nil
}

View File

@ -1,5 +1,323 @@
package ca
// func GenerateSi1gnature(paramMap map[string]string, secret string) string {
//
// }
import (
"errors"
"hospital-admin-api/config"
"net/url"
)
// EditCloudCertRequestData 修改云证书请求数据
type EditCloudCertRequestData struct {
EntityId string `json:"entityId"` // 用户唯一标识,由业务系统定义
EntityType string `json:"entityType"` // 用户类型,可选值[Personal/Organizational]
PersonalPhone string `json:"personalPhone"` // 联系人电话
PersonalName string `json:"personalName"` // 个人姓名类型为Personal时必填
PersonalIdNumber string `json:"personalIdNumber"` // 个人证件号类型为Personal时必填
OrgName string `json:"orgName"` // 组织机构名称信用代码类型为Organizational时必填
OrgNumber string `json:"orgNumber"` // 组织机构代码信用代码类型为Organizational时必填
Pin string `json:"pin"` // 证书PIN码
OrgDept string `json:"orgDept"` // 卫生证书:医院部门
Province string `json:"province"` // 卫生证书:省、州
Locality string `json:"locality"` // 卫生证书:城市
AuthType string `json:"authType"` // 委托鉴证方式[实人认证、线下认证、其它方式认证]
AuthTime string `json:"authTime"` // 委托鉴证时间(鉴证完成的时间戳)单位:秒
AuthResult string `json:"authResult"` // 委托鉴证结果[认证通过]
AuthNoticeType string `json:"authNoticeType"` // 委托鉴证告知类型[数字证书申请告知]
}
// AddCloudCertRequestData 新增云证书请求数据
type AddCloudCertRequestData struct {
EntityId string `json:"entityId"` // 用户唯一标识,由业务系统定义
EntityType string `json:"entityType"` // 用户类型,可选值[Personal/Organizational]
PersonalPhone string `json:"personalPhone"` // 联系人电话
PersonalName string `json:"personalName"` // 个人姓名类型为Personal时必填
PersonalIdNumber string `json:"personalIdNumber"` // 个人证件号类型为Personal时必填
OrgName string `json:"orgName"` // 组织机构名称信用代码类型为Organizational时必填
OrgNumber string `json:"orgNumber"` // 组织机构代码信用代码类型为Organizational时必填
Pin string `json:"pin"` // 证书PIN码
OrgDept string `json:"orgDept"` // 卫生证书:医院部门
Province string `json:"province"` // 卫生证书:省、州
Locality string `json:"locality"` // 卫生证书:城市
AuthType string `json:"authType"` // 委托鉴证方式[实人认证、线下认证、其它方式认证]
AuthTime string `json:"authTime"` // 委托鉴证时间(鉴证完成的时间戳)单位:秒
AuthResult string `json:"authResult"` // 委托鉴证结果[认证通过]
AuthNoticeType string `json:"authNoticeType"` // 委托鉴证告知类型[数字证书申请告知]
}
// GetUserSignConfigRequestData 获取用户签章图片
type GetUserSignConfigRequestData struct {
UserId string `json:"userId"` // 用户标识信息
}
// DeleteUserSignConfigRequestData 删除签章配置
type DeleteUserSignConfigRequestData struct {
UserId string `json:"userId"` // 用户标识信息
ConfigKey string `json:"configKey"` // 签章配置唯一标识
}
// EditCloudCertResponse 修改云证书返回数据
type EditCloudCertResponse struct {
CertBase64 string `json:"certBase64"` // 签名值证书
CertP7 string `json:"certP7"` // 证书链
CertSerialnumber string `json:"certSerialnumber"` // 证书序列号
}
// AddCloudCertResponse 申请云证书返回数据
type AddCloudCertResponse struct {
CertBase64 string `json:"certBase64"` // 签名值证书
CertP7 string `json:"certP7"` // 证书链
CertSerialnumber string `json:"certSerialnumber"` // 证书序列号
}
// GetUserSignConfigResponse 获取用户签章图片返回数据
type GetUserSignConfigResponse struct {
SealImg string `json:"sealImg"` // 印章图片
SealType int `json:"sealType"` // 印章类型(1公章;2财务章;3个人章;4合同印章;5其他)
AppId string `json:"appId"` // 应用appid
Id string `json:"id"` // 印章唯一标识
}
// EditCloudCert 修改云证书
func EditCloudCert(d *EditCloudCertRequestData) (*EditCloudCertResponse, error) {
if d == nil {
return nil, errors.New("修改云证书失败")
}
// 获取签名
requestDataMap := make(map[string]interface{})
requestDataMap["entityId"] = d.EntityId
requestDataMap["entityType"] = d.EntityType
requestDataMap["personalPhone"] = d.PersonalPhone
requestDataMap["personalName"] = d.PersonalName
requestDataMap["personalIdNumber"] = d.PersonalIdNumber
requestDataMap["orgName"] = d.OrgName
requestDataMap["orgNumber"] = d.OrgNumber
requestDataMap["pin"] = d.Pin
requestDataMap["province"] = d.Province
requestDataMap["locality"] = d.Locality
requestDataMap["authType"] = d.AuthType
requestDataMap["authTime"] = d.AuthTime
requestDataMap["authResult"] = d.AuthResult
requestDataMap["authNoticeType"] = d.AuthNoticeType
signature := GenerateSignature(requestDataMap)
if signature == "" {
return nil, errors.New("云证书签名错误")
}
formData := url.Values{}
formData.Set("entityId", d.EntityId)
formData.Set("entityType", d.EntityType)
formData.Set("personalPhone", d.PersonalPhone)
formData.Set("personalName", d.PersonalName)
formData.Set("personalIdNumber", d.PersonalIdNumber)
formData.Set("orgName", d.OrgName)
formData.Set("orgNumber", d.OrgNumber)
formData.Set("pin", d.Pin)
formData.Set("province", d.Province)
formData.Set("locality", d.Locality)
formData.Set("authType", d.AuthType)
formData.Set("authTime", d.AuthTime)
formData.Set("authResult", d.AuthResult)
formData.Set("authNoticeType", d.AuthNoticeType)
// 构建请求 URL
requestUrl := config.C.CaOnline.CaOnlineApiUrl + "/cloud-certificate-service/api/cloudCert/open/v2/cert/certChange"
response, err := postRequest(requestUrl, formData, signature)
if err != nil {
return nil, errors.New(err.Error())
}
certBase64, ok := response["certBase64"]
if !ok {
return nil, errors.New("返回数据错误")
}
certP7, ok := response["certP7"]
if !ok {
return nil, errors.New("返回数据错误")
}
certSerialnumber, ok := response["certSerialnumber"]
if !ok {
return nil, errors.New("返回数据错误")
}
result := &EditCloudCertResponse{
CertBase64: certBase64.(string),
CertP7: certP7.(string),
CertSerialnumber: certSerialnumber.(string),
}
return result, nil
}
// AddCloudCert 新增云证书
func AddCloudCert(d *AddCloudCertRequestData) (*AddCloudCertResponse, error) {
if d == nil {
return nil, errors.New("修改云证书失败")
}
// 获取签名
requestDataMap := make(map[string]interface{})
requestDataMap["entityId"] = d.EntityId
requestDataMap["entityType"] = d.EntityType
requestDataMap["personalPhone"] = d.PersonalPhone
requestDataMap["personalName"] = d.PersonalName
requestDataMap["personalIdNumber"] = d.PersonalIdNumber
requestDataMap["orgName"] = d.OrgName
requestDataMap["orgNumber"] = d.OrgNumber
requestDataMap["pin"] = d.Pin
requestDataMap["province"] = d.Province
requestDataMap["locality"] = d.Locality
requestDataMap["authType"] = d.AuthType
requestDataMap["authTime"] = d.AuthTime
requestDataMap["authResult"] = d.AuthResult
requestDataMap["authNoticeType"] = d.AuthNoticeType
signature := GenerateSignature(requestDataMap)
if signature == "" {
return nil, errors.New("云证书签名错误")
}
formData := url.Values{}
formData.Set("entityId", d.EntityId)
formData.Set("entityType", d.EntityType)
formData.Set("personalPhone", d.PersonalPhone)
formData.Set("personalName", d.PersonalName)
formData.Set("personalIdNumber", d.PersonalIdNumber)
formData.Set("orgName", d.OrgName)
formData.Set("orgNumber", d.OrgNumber)
formData.Set("pin", d.Pin)
formData.Set("province", d.Province)
formData.Set("locality", d.Locality)
formData.Set("authType", d.AuthType)
formData.Set("authTime", d.AuthTime)
formData.Set("authResult", d.AuthResult)
formData.Set("authNoticeType", d.AuthNoticeType)
// 构建请求 URL
requestUrl := config.C.CaOnline.CaOnlineApiUrl + "/cloud-certificate-service/api/cloudCert/open/v2/cert/certEnroll"
response, err := postRequest(requestUrl, formData, signature)
if err != nil {
return nil, errors.New(err.Error())
}
certBase64, ok := response["certBase64"]
if !ok {
return nil, errors.New("返回数据错误")
}
certP7, ok := response["certP7"]
if !ok {
return nil, errors.New("返回数据错误")
}
certSerialnumber, ok := response["certSerialnumber"]
if !ok {
return nil, errors.New("返回数据错误")
}
result := &AddCloudCertResponse{
CertBase64: certBase64.(string),
CertP7: certP7.(string),
CertSerialnumber: certSerialnumber.(string),
}
return result, nil
}
// GetUserSignConfig 获取用户签章图片
func GetUserSignConfig(d *GetUserSignConfigRequestData) (*GetUserSignConfigResponse, error) {
if d == nil {
return nil, errors.New("修改云证书失败")
}
// 获取签名
requestDataMap := make(map[string]interface{})
requestDataMap["userId"] = d.UserId
signature := GenerateSignature(requestDataMap)
if signature == "" {
return nil, errors.New("云证书签名错误")
}
formData := url.Values{}
formData.Set("userId", d.UserId)
// 构建请求 URL
requestUrl := config.C.CaOnline.CaOnlineApiUrl + "/signature-server/api/open/signature/fetchUserSeal"
response, err := postRequest(requestUrl, formData, signature)
if err != nil {
return nil, errors.New(err.Error())
}
// 返回内容为空,未设置签章图片
if response == nil {
return nil, nil
}
sealImg, ok := response["sealImg"]
if !ok {
return nil, errors.New("返回数据错误")
}
sealType, ok := response["sealType"]
if !ok {
return nil, errors.New("返回数据错误")
}
appId, ok := response["appId"]
if !ok {
return nil, errors.New("返回数据错误")
}
id, ok := response["id"]
if !ok {
return nil, errors.New("返回数据错误")
}
result := &GetUserSignConfigResponse{
SealImg: sealImg.(string),
SealType: sealType.(int),
AppId: appId.(string),
Id: id.(string),
}
return result, nil
}
// DeleteUserSignConfig 删除签章配置
func DeleteUserSignConfig(d *DeleteUserSignConfigRequestData) (bool, error) {
if d == nil {
return false, errors.New("修改云证书失败")
}
// 获取签名
requestDataMap := make(map[string]interface{})
requestDataMap["userId"] = d.UserId
signature := GenerateSignature(requestDataMap)
if signature == "" {
return false, errors.New("云证书签名错误")
}
formData := url.Values{}
formData.Set("userId", d.UserId)
formData.Set("configKey", d.ConfigKey)
// 构建请求 URL
requestUrl := config.C.CaOnline.CaOnlineApiUrl + "/signature-server/api/open/signature/delSignConfig"
response, err := postRequest(requestUrl, formData, signature)
if err != nil {
return false, errors.New(err.Error())
}
// 返回内容为空
if response == nil {
return true, nil
}
return true, nil
}

View File

@ -0,0 +1,422 @@
package tencentIm
import (
"bytes"
"compress/zlib"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"io/ioutil"
"strconv"
"strings"
"time"
)
/**
*功能说明用于签发 TRTC IM 服务中必须要使用的 UserSig 鉴权票据
*
*参数说明
* sdkappid - 应用id
* key - 计算 usersig 用的加密密钥,控制台可获取
* userid - 用户id限制长度为32字节只允许包含大小写英文字母a-zA-Z数字0-9及下划线和连词符
* expire - UserSig 票据的过期时间单位是秒比如 86400 代表生成的 UserSig 票据在一天后就无法再使用了
*/
// GenUserSig /**
func GenUserSig(sdkappid int, key string, userid string, expire int) (string, error) {
return genSig(sdkappid, key, userid, expire, nil)
}
func GenUserSigWithBuf(sdkappid int, key string, userid string, expire int, buf []byte) (string, error) {
return genSig(sdkappid, key, userid, expire, buf)
}
/**
*功能说明
* 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据
* PrivateMapKey 需要跟 UserSig 一起使用 PrivateMapKey UserSig 有更强的权限控制能力
* - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限只要 UserSig 正确其对应的 UserID 可以进出任意房间
* - PrivateMapKey 则是将 UserID 的权限控制的更加严格包括能不能进入某个房间能不能在该房间里上行音视频等等
* 如果要开启 PrivateMapKey 严格权限位校验需要在实时音视频控制台=>应用管理=>应用信息中打开启动权限密钥开关
*
*参数说明
* sdkappid - 应用id
* key - 计算 usersig 用的加密密钥,控制台可获取
* userid - 用户id限制长度为32字节只允许包含大小写英文字母a-zA-Z数字0-9及下划线和连词符
* expire - PrivateMapKey 票据的过期时间单位是秒比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了
* roomid - 房间号用于指定该 userid 可以进入的房间号
* privilegeMap - 权限位使用了一个字节中的 8 个比特位分别代表八个具体的功能权限开关
* - 1 0000 0001 = 1创建房间的权限
* - 2 0000 0010 = 2加入房间的权限
* - 3 0000 0100 = 4发送语音的权限
* - 4 0000 1000 = 8接收语音的权限
* - 5 0001 0000 = 16发送视频的权限
* - 6 0010 0000 = 32接收视频的权限
* - 7 0100 0000 = 64发送辅路也就是屏幕分享视频的权限
* - 8 1000 0000 = 200接收辅路也就是屏幕分享视频的权限
* - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限
* - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限但不具备其他权限
*/
/**
* Function:
* Used to issue PrivateMapKey that is optional for room entry.
* PrivateMapKey must be used together with UserSig but with more powerful permission control capabilities.
* - UserSig can only control whether a UserID has permission to use the TRTC service. As long as the UserSig is correct, the user with the corresponding UserID can enter or leave any room.
* - PrivateMapKey specifies more stringent permissions for a UserID, including whether the UserID can be used to enter a specific room and perform audio/video upstreaming in the room.
* To enable stringent PrivateMapKey permission bit verification, you need to enable permission key in TRTC console > Application Management > Application Info.
*
* Parameter description:
* sdkappid - Application ID
* userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-).
* key - The encryption key used to calculate usersig can be obtained from the console.
* roomid - ID of the room to which the specified UserID can enter.
* expire - PrivateMapKey expiration time, in seconds. For example, 86400 indicates that the generated PrivateMapKey will expire one day after being generated.
* privilegeMap - Permission bits. Eight bits in the same byte are used as the permission switches of eight specific features:
* - Bit 1: 0000 0001 = 1, permission for room creation
* - Bit 2: 0000 0010 = 2, permission for room entry
* - Bit 3: 0000 0100 = 4, permission for audio sending
* - Bit 4: 0000 1000 = 8, permission for audio receiving
* - Bit 5: 0001 0000 = 16, permission for video sending
* - Bit 6: 0010 0000 = 32, permission for video receiving
* - Bit 7: 0100 0000 = 64, permission for substream video sending (screen sharing)
* - Bit 8: 1000 0000 = 200, permission for substream video receiving (screen sharing)
* - privilegeMap == 1111 1111 == 255: Indicates that the UserID has all feature permissions of the room specified by roomid.
* - privilegeMap == 0010 1010 == 42: Indicates that the UserID has only the permissions to enter the room and receive audio/video data.
*/
func GenPrivateMapKey(sdkappid int, key string, userid string, expire int, roomid uint32, privilegeMap uint32) (string, error) {
var userbuf []byte = genUserBuf(userid, sdkappid, roomid, expire, privilegeMap, 0, "")
return genSig(sdkappid, key, userid, expire, userbuf)
}
/**
*功能说明
* 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据
* PrivateMapKey 需要跟 UserSig 一起使用 PrivateMapKey UserSig 有更强的权限控制能力
* - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限只要 UserSig 正确其对应的 UserID 可以进出任意房间
* - PrivateMapKey 则是将 UserID 的权限控制的更加严格包括能不能进入某个房间能不能在该房间里上行音视频等等
* 如果要开启 PrivateMapKey 严格权限位校验需要在实时音视频控制台=>应用管理=>应用信息中打开启动权限密钥开关
*
*参数说明
* sdkappid - 应用id
* key - 计算 usersig 用的加密密钥,控制台可获取
* userid - 用户id限制长度为32字节只允许包含大小写英文字母a-zA-Z数字0-9及下划线和连词符
* expire - PrivateMapKey 票据的过期时间单位是秒比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了
* roomStr - 字符串房间号用于指定该 userid 可以进入的房间号
* privilegeMap - 权限位使用了一个字节中的 8 个比特位分别代表八个具体的功能权限开关
* - 1 0000 0001 = 1创建房间的权限
* - 2 0000 0010 = 2加入房间的权限
* - 3 0000 0100 = 4发送语音的权限
* - 4 0000 1000 = 8接收语音的权限
* - 5 0001 0000 = 16发送视频的权限
* - 6 0010 0000 = 32接收视频的权限
* - 7 0100 0000 = 64发送辅路也就是屏幕分享视频的权限
* - 8 1000 0000 = 200接收辅路也就是屏幕分享视频的权限
* - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限
* - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限但不具备其他权限
*/
/**
* Function:
* Used to issue PrivateMapKey that is optional for room entry.
* PrivateMapKey must be used together with UserSig but with more powerful permission control capabilities.
* - UserSig can only control whether a UserID has permission to use the TRTC service. As long as the UserSig is correct, the user with the corresponding UserID can enter or leave any room.
* - PrivateMapKey specifies more stringent permissions for a UserID, including whether the UserID can be used to enter a specific room and perform audio/video upstreaming in the room.
* To enable stringent PrivateMapKey permission bit verification, you need to enable permission key in TRTC console > Application Management > Application Info.
*
* Parameter description:
* sdkappid - Application ID
* userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-).
* key - The encryption key used to calculate usersig can be obtained from the console.
* roomstr - ID of the room to which the specified UserID can enter.
* expire - PrivateMapKey expiration time, in seconds. For example, 86400 indicates that the generated PrivateMapKey will expire one day after being generated.
* privilegeMap - Permission bits. Eight bits in the same byte are used as the permission switches of eight specific features:
* - Bit 1: 0000 0001 = 1, permission for room creation
* - Bit 2: 0000 0010 = 2, permission for room entry
* - Bit 3: 0000 0100 = 4, permission for audio sending
* - Bit 4: 0000 1000 = 8, permission for audio receiving
* - Bit 5: 0001 0000 = 16, permission for video sending
* - Bit 6: 0010 0000 = 32, permission for video receiving
* - Bit 7: 0100 0000 = 64, permission for substream video sending (screen sharing)
* - Bit 8: 1000 0000 = 200, permission for substream video receiving (screen sharing)
* - privilegeMap == 1111 1111 == 255: Indicates that the UserID has all feature permissions of the room specified by roomid.
* - privilegeMap == 0010 1010 == 42: Indicates that the UserID has only the permissions to enter the room and receive audio/video data.
*/
func GenPrivateMapKeyWithStringRoomID(sdkappid int, key string, userid string, expire int, roomStr string, privilegeMap uint32) (string, error) {
var userbuf []byte = genUserBuf(userid, sdkappid, 0, expire, privilegeMap, 0, roomStr)
return genSig(sdkappid, key, userid, expire, userbuf)
}
func genUserBuf(account string, dwSdkappid int, dwAuthID uint32,
dwExpTime int, dwPrivilegeMap uint32, dwAccountType uint32, roomStr string) []byte {
offset := 0
length := 1 + 2 + len(account) + 20 + len(roomStr)
if len(roomStr) > 0 {
length = length + 2
}
userBuf := make([]byte, length)
// ver
if len(roomStr) > 0 {
userBuf[offset] = 1
} else {
userBuf[offset] = 0
}
offset++
userBuf[offset] = (byte)((len(account) & 0xFF00) >> 8)
offset++
userBuf[offset] = (byte)(len(account) & 0x00FF)
offset++
for ; offset < len(account)+3; offset++ {
userBuf[offset] = account[offset-3]
}
// dwSdkAppid
userBuf[offset] = (byte)((dwSdkappid & 0xFF000000) >> 24)
offset++
userBuf[offset] = (byte)((dwSdkappid & 0x00FF0000) >> 16)
offset++
userBuf[offset] = (byte)((dwSdkappid & 0x0000FF00) >> 8)
offset++
userBuf[offset] = (byte)(dwSdkappid & 0x000000FF)
offset++
// dwAuthId
userBuf[offset] = (byte)((dwAuthID & 0xFF000000) >> 24)
offset++
userBuf[offset] = (byte)((dwAuthID & 0x00FF0000) >> 16)
offset++
userBuf[offset] = (byte)((dwAuthID & 0x0000FF00) >> 8)
offset++
userBuf[offset] = (byte)(dwAuthID & 0x000000FF)
offset++
// dwExpTime now+300;
currTime := time.Now().Unix()
var expire = currTime + int64(dwExpTime)
userBuf[offset] = (byte)((expire & 0xFF000000) >> 24)
offset++
userBuf[offset] = (byte)((expire & 0x00FF0000) >> 16)
offset++
userBuf[offset] = (byte)((expire & 0x0000FF00) >> 8)
offset++
userBuf[offset] = (byte)(expire & 0x000000FF)
offset++
// dwPrivilegeMap
userBuf[offset] = (byte)((dwPrivilegeMap & 0xFF000000) >> 24)
offset++
userBuf[offset] = (byte)((dwPrivilegeMap & 0x00FF0000) >> 16)
offset++
userBuf[offset] = (byte)((dwPrivilegeMap & 0x0000FF00) >> 8)
offset++
userBuf[offset] = (byte)(dwPrivilegeMap & 0x000000FF)
offset++
// dwAccountType
userBuf[offset] = (byte)((dwAccountType & 0xFF000000) >> 24)
offset++
userBuf[offset] = (byte)((dwAccountType & 0x00FF0000) >> 16)
offset++
userBuf[offset] = (byte)((dwAccountType & 0x0000FF00) >> 8)
offset++
userBuf[offset] = (byte)(dwAccountType & 0x000000FF)
offset++
if len(roomStr) > 0 {
userBuf[offset] = (byte)((len(roomStr) & 0xFF00) >> 8)
offset++
userBuf[offset] = (byte)(len(roomStr) & 0x00FF)
offset++
for ; offset < length; offset++ {
userBuf[offset] = roomStr[offset-(length-len(roomStr))]
}
}
return userBuf
}
func hmacsha256(sdkappid int, key string, identifier string, currTime int64, expire int, base64UserBuf *string) string {
var contentToBeSigned string
contentToBeSigned = "TLS.identifier:" + identifier + "\n"
contentToBeSigned += "TLS.sdkappid:" + strconv.Itoa(sdkappid) + "\n"
contentToBeSigned += "TLS.time:" + strconv.FormatInt(currTime, 10) + "\n"
contentToBeSigned += "TLS.expire:" + strconv.Itoa(expire) + "\n"
if nil != base64UserBuf {
contentToBeSigned += "TLS.userbuf:" + *base64UserBuf + "\n"
}
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(contentToBeSigned))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
func genSig(sdkappid int, key string, identifier string, expire int, userbuf []byte) (string, error) {
currTime := time.Now().Unix()
sigDoc := make(map[string]interface{})
sigDoc["TLS.ver"] = "2.0"
sigDoc["TLS.identifier"] = identifier
sigDoc["TLS.sdkappid"] = sdkappid
sigDoc["TLS.expire"] = expire
sigDoc["TLS.time"] = currTime
var base64UserBuf string
if nil != userbuf {
base64UserBuf = base64.StdEncoding.EncodeToString(userbuf)
sigDoc["TLS.userbuf"] = base64UserBuf
sigDoc["TLS.sig"] = hmacsha256(sdkappid, key, identifier, currTime, expire, &base64UserBuf)
} else {
sigDoc["TLS.sig"] = hmacsha256(sdkappid, key, identifier, currTime, expire, nil)
}
data, err := json.Marshal(sigDoc)
if err != nil {
return "", err
}
var b bytes.Buffer
w := zlib.NewWriter(&b)
if _, err = w.Write(data); err != nil {
return "", err
}
if err = w.Close(); err != nil {
return "", err
}
return base64urlEncode(b.Bytes()), nil
}
// VerifyUserSig 检验UserSig在now时间点时是否有效
// VerifyUserSig Check if UserSig is valid at now time
func VerifyUserSig(sdkappid uint64, key string, userid string, usersig string, now time.Time) error {
sig, err := newUserSig(usersig)
if err != nil {
return err
}
return sig.verify(sdkappid, key, userid, now, nil)
}
// VerifyUserSigWithBuf 检验带UserBuf的UserSig在now时间点是否有效
// VerifyUserSigWithBuf Check if UserSig with UserBuf is valid at now
func VerifyUserSigWithBuf(sdkappid uint64, key string, userid string, usersig string, now time.Time, userbuf []byte) error {
sig, err := newUserSig(usersig)
if err != nil {
return err
}
return sig.verify(sdkappid, key, userid, now, userbuf)
}
type userSig struct {
Version string `json:"TLS.ver,omitempty"`
Identifier string `json:"TLS.identifier,omitempty"`
SdkAppID uint64 `json:"TLS.sdkappid,omitempty"`
Expire int64 `json:"TLS.expire,omitempty"`
Time int64 `json:"TLS.time,omitempty"`
UserBuf []byte `json:"TLS.userbuf,omitempty"`
Sig string `json:"TLS.sig,omitempty"`
}
func newUserSig(usersig string) (userSig, error) {
b, err := base64urlDecode(usersig)
if err != nil {
return userSig{}, err
}
r, err := zlib.NewReader(bytes.NewReader(b))
if err != nil {
return userSig{}, err
}
data, err := ioutil.ReadAll(r)
if err != nil {
return userSig{}, err
}
if err = r.Close(); err != nil {
return userSig{}, err
}
var sig userSig
if err = json.Unmarshal(data, &sig); err != nil {
return userSig{}, nil
}
return sig, nil
}
func (u userSig) verify(sdkappid uint64, key string, userid string, now time.Time, userbuf []byte) error {
if sdkappid != u.SdkAppID {
return ErrSdkAppIDNotMatch
}
if userid != u.Identifier {
return ErrIdentifierNotMatch
}
if now.Unix() > u.Time+u.Expire {
return ErrExpired
}
if userbuf != nil {
if u.UserBuf == nil {
return ErrUserBufTypeNotMatch
}
if !bytes.Equal(userbuf, u.UserBuf) {
return ErrUserBufNotMatch
}
} else if u.UserBuf != nil {
return ErrUserBufTypeNotMatch
}
if u.sign(key) != u.Sig {
return ErrSigNotMatch
}
return nil
}
func (u userSig) sign(key string) string {
var sb bytes.Buffer
sb.WriteString("TLS.identifier:")
sb.WriteString(u.Identifier)
sb.WriteString("\n")
sb.WriteString("TLS.sdkappid:")
sb.WriteString(strconv.FormatUint(u.SdkAppID, 10))
sb.WriteString("\n")
sb.WriteString("TLS.time:")
sb.WriteString(strconv.FormatInt(u.Time, 10))
sb.WriteString("\n")
sb.WriteString("TLS.expire:")
sb.WriteString(strconv.FormatInt(u.Expire, 10))
sb.WriteString("\n")
if u.UserBuf != nil {
sb.WriteString("TLS.userbuf:")
sb.WriteString(base64.StdEncoding.EncodeToString(u.UserBuf))
sb.WriteString("\n")
}
h := hmac.New(sha256.New, []byte(key))
h.Write(sb.Bytes())
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
func base64urlEncode(data []byte) string {
str := base64.StdEncoding.EncodeToString(data)
str = strings.Replace(str, "+", "*", -1)
str = strings.Replace(str, "/", "-", -1)
str = strings.Replace(str, "=", "_", -1)
return str
}
func base64urlDecode(str string) ([]byte, error) {
str = strings.Replace(str, "_", "=", -1)
str = strings.Replace(str, "-", "/", -1)
str = strings.Replace(str, "*", "+", -1)
return base64.StdEncoding.DecodeString(str)
}
// 错误类型
var (
ErrSdkAppIDNotMatch = errors.New("sdk appid not match")
ErrIdentifierNotMatch = errors.New("identifier not match")
ErrExpired = errors.New("expired")
ErrUserBufTypeNotMatch = errors.New("userbuf type not match")
ErrUserBufNotMatch = errors.New("userbuf not match")
ErrSigNotMatch = errors.New("sig not match")
)

94
extend/tencentIm/base.go Normal file
View File

@ -0,0 +1,94 @@
package tencentIm
import (
"bytes"
"encoding/json"
"errors"
"hospital-admin-api/config"
"io"
"math/rand"
"net/http"
"net/url"
"strconv"
"time"
)
// GetUserSign 获取签名
func GetUserSign(userId string) (string, error) {
if userId == "" {
userId = "administrator"
}
ImAppID := config.C.Im.ImAppID
ImSecret := config.C.Im.ImSecret
sign, err := GenUserSig(ImAppID, ImSecret, userId, 86400*180)
if err != nil || sign == "" {
return "", errors.New("签名获取失败")
}
return sign, err
}
// 获取请求链接
func getRequestUrlParams(userId string) (bool, string) {
// 获取签名
// 获取签名
sign, err := GetUserSign(userId)
if err != nil {
return false, err.Error()
}
rand.Seed(time.Now().UnixNano())
params := url.Values{}
params.Set("sdkappid", strconv.Itoa(config.C.Im.ImAppID))
params.Set("identifier", "administrator")
params.Set("usersig", sign)
params.Set("random", strconv.Itoa(rand.Intn(4294967296)))
params.Set("contenttype", "json")
queryString := params.Encode()
return true, queryString
}
// 统一请求
func postRequest(url string, requestBody []byte) (map[string]interface{}, error) {
responseMap := make(map[string]interface{})
// 发起 POST 请求
resp, err := http.Post(url, "application/json", bytes.NewBuffer(requestBody))
if err != nil {
return nil, err
}
defer func(Body io.ReadCloser) {
_ = Body.Close()
}(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
err = json.Unmarshal([]byte(string(body)), &responseMap)
if err != nil {
// json解析失败
return nil, err
}
if responseMap == nil {
return nil, errors.New("请求im失败")
}
if errorCode, ok := responseMap["ErrorCode"]; ok {
if errorCode != 0 {
if errorInfo, ok := responseMap["ErrorInfo"].(string); ok {
return nil, errors.New(errorInfo)
} else {
return nil, errors.New("请求im失败")
}
}
}
return responseMap, nil
}

View File

@ -0,0 +1,53 @@
// Package tencentIm im资料
package tencentIm
import (
"encoding/json"
"errors"
"hospital-admin-api/config"
)
// ProfileItem 资料对象数组
type ProfileItem struct {
Tag string `json:"Tag"`
Value string `json:"Value"`
}
// PortraitSetRequest 请求格式
type PortraitSetRequest struct {
FromAccount string `json:"From_Account"`
ProfileItems []ProfileItem `json:"ProfileItem"`
}
// SetProfile 设置账户资料
func SetProfile(userId string, profileItem []ProfileItem) (bool, error) {
if len(profileItem) == 0 {
return false, errors.New("未设置资料")
}
// 构建请求数据
requestData := &PortraitSetRequest{
FromAccount: userId,
ProfileItems: profileItem,
}
// 将请求数据转换为 JSON
requestBody, err := json.Marshal(requestData)
if err != nil {
return false, errors.New("设置im资料失败")
}
// 构建请求 URL
res, result := getRequestUrlParams("administrator")
if res != true {
return false, errors.New(result)
}
url := config.C.Im.ImBaseUrl + "v4/profile/portrait_set?" + result
_, err = postRequest(url, requestBody)
if err != nil {
return false, errors.New(err.Error())
}
return true, nil
}

1
go.mod
View File

@ -56,6 +56,7 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/tencentcloud/tencentcloud-sdk-go v3.0.233+incompatible // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
golang.org/x/arch v0.3.0 // indirect

2
go.sum
View File

@ -256,6 +256,8 @@ github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gt
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/tencentcloud/tencentcloud-sdk-go v3.0.233+incompatible h1:q+D/Y9jla3afgsIihtyhwyl0c2W+eRWNM9ohVwPiiPw=
github.com/tencentcloud/tencentcloud-sdk-go v3.0.233+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=