Skip to content

Commit b65a63d

Browse files
zuohuaijungitee-org
authored andcommitted
!1036 钉钉插件优化
Merge pull request !1036 from Hans/SyncDingTalkUserJob2
2 parents a27a7c6 + 9f00d49 commit b65a63d

File tree

5 files changed

+213
-148
lines changed

5 files changed

+213
-148
lines changed

Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Admin.NET.Plugin.DingTalk.csproj

+4
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,8 @@
2525
</None>
2626
</ItemGroup>
2727

28+
<ItemGroup>
29+
<Folder Include="Job\" />
30+
</ItemGroup>
31+
2832
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
// 大名科技(天津)有限公司 版权所有
2+
//
3+
// 此源代码遵循位于源代码树根目录中的 LICENSE 文件的许可证
4+
//
5+
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动
6+
//
7+
// 任何基于本项目二次开发而产生的一切法律纠纷和责任,均与作者无关
8+
9+
using Admin.NET.Plugin.DingTalk;
10+
using Furion.Schedule;
11+
using Microsoft.Extensions.DependencyInjection;
12+
using Microsoft.Extensions.Logging;
13+
14+
namespace Admin.NET.Plugin.Job;
15+
16+
17+
/// <summary>
18+
/// 同步钉钉用户job
19+
/// </summary>
20+
[JobDetail("SyncDingTalkUserJob", Description = "同步钉钉用户", GroupName = "default", Concurrent = false)]
21+
[Daily(TriggerId = "SyncDingTalkUserTrigger", Description = "同步钉钉用户")]
22+
public class SyncDingTalkUserJob : IJob
23+
{
24+
private readonly IServiceScopeFactory _scopeFactory;
25+
private readonly IDingTalkApi _dingTalkApi;
26+
private readonly ILogger _logger;
27+
public SyncDingTalkUserJob(IServiceScopeFactory scopeFactory, IDingTalkApi dingTalkApi, ILoggerFactory loggerFactory)
28+
{
29+
_scopeFactory = scopeFactory;
30+
_dingTalkApi = dingTalkApi;
31+
_logger = loggerFactory.CreateLogger("System.Logging.LoggingMonitor");
32+
}
33+
34+
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
35+
{
36+
using var serviceScope = _scopeFactory.CreateScope();
37+
var _sysUserRep = serviceScope.ServiceProvider.GetRequiredService<SqlSugarRepository<SysUser>>();
38+
var _dingTalkUserRepo = serviceScope.ServiceProvider.GetRequiredService<SqlSugarRepository<DingTalkUser>>();
39+
var _dingTalkOptions = serviceScope.ServiceProvider.GetRequiredService<IOptions<DingTalkOptions>>();
40+
// 获取token
41+
var tokenRes = await _dingTalkApi.GetDingTalkToken(_dingTalkOptions.Value.ClientId, _dingTalkOptions.Value.ClientSecret);
42+
if (tokenRes.ErrCode != 0)
43+
{
44+
throw Oops.Oh(tokenRes.ErrMsg);
45+
}
46+
var dingTalkUserList = new List<DingTalkEmpRosterFieldVo>();
47+
var offset = 0;
48+
while (offset >= 0)
49+
{
50+
// 获取用户id列表
51+
var userIdsRes = await _dingTalkApi.GetDingTalkCurrentEmployeesList(tokenRes.AccessToken, new GetDingTalkCurrentEmployeesListInput
52+
{
53+
StatusList = "2,3,5,-1",
54+
Size = 50,
55+
Offset = offset
56+
});
57+
if (!userIdsRes.Success)
58+
{
59+
_logger.LogError(userIdsRes.ErrMsg);
60+
break;
61+
}
62+
// 根据用户id获取花名册
63+
var rosterRes = await _dingTalkApi.GetDingTalkCurrentEmployeesRosterList(tokenRes.AccessToken, new GetDingTalkCurrentEmployeesRosterListInput()
64+
{
65+
UserIdList = string.Join(",", userIdsRes.Result.DataList),
66+
FieldFilterList = $"{DingTalkConst.NameField},{DingTalkConst.JobNumberField},{DingTalkConst.MobileField}",
67+
AgentId = _dingTalkOptions.Value.AgentId
68+
});
69+
if (!rosterRes.Success)
70+
{
71+
_logger.LogError(rosterRes.ErrMsg);
72+
break;
73+
}
74+
dingTalkUserList.AddRange(rosterRes.Result);
75+
if (userIdsRes.Result.NextCursor == null)
76+
{
77+
break;
78+
}
79+
// 保存分页游标
80+
offset = (int)userIdsRes.Result.NextCursor;
81+
}
82+
83+
// 判断新增还是更新
84+
var sysDingTalkUserIdList = await _dingTalkUserRepo.AsQueryable()
85+
.Select(x => new
86+
{
87+
x.Id,
88+
x.DingTalkUserId
89+
})
90+
.ToListAsync();
91+
// 需要更新的用户id
92+
var uDingTalkUser = dingTalkUserList.Where(x => sysDingTalkUserIdList.Any(d => d.DingTalkUserId == x.UserId));
93+
// 需要新增的用户id
94+
var iDingTalkUser = dingTalkUserList.Where(u => !sysDingTalkUserIdList.Any(d => d.DingTalkUserId == u.UserId));
95+
#region 新增钉钉用户
96+
var iUser = iDingTalkUser
97+
.Select(res => new DingTalkUser
98+
{
99+
DingTalkUserId = res.UserId,
100+
Name = res.FieldDataList
101+
.Where(f => f.FieldCode == DingTalkConst.NameField)
102+
.Select(f => f.FieldValueList.Select(v => v.Value).FirstOrDefault())
103+
.FirstOrDefault(),
104+
Mobile = res.FieldDataList
105+
.Where(f => f.FieldCode == DingTalkConst.MobileField)
106+
.Select(f => f.FieldValueList.Select(v => v.Value).FirstOrDefault())
107+
.FirstOrDefault(),
108+
JobNumber = res.FieldDataList
109+
.Where(f => f.FieldCode == DingTalkConst.JobNumberField)
110+
.Select(f => f.FieldValueList.Select(v => v.Value).FirstOrDefault())
111+
.FirstOrDefault(),
112+
}).ToList();
113+
if (iUser.Count > 0)
114+
{
115+
var iUserRes = await _dingTalkUserRepo.CopyNew().AsInsertable(iUser).ExecuteCommandAsync();
116+
if (iUserRes <= 0)
117+
{
118+
throw Oops.Oh("保存钉钉用户错误");
119+
}
120+
}
121+
#endregion
122+
123+
#region 更新钉钉用户
124+
var uUser = uDingTalkUser
125+
.Select(res => new DingTalkUser
126+
{
127+
Id = sysDingTalkUserIdList.Where(d => d.DingTalkUserId == res.UserId).Select(d => d.Id).FirstOrDefault(),
128+
DingTalkUserId = res.UserId,
129+
Name = res.FieldDataList
130+
.Where(f => f.FieldCode == DingTalkConst.NameField)
131+
.Select(f => f.FieldValueList.Select(v => v.Value).FirstOrDefault())
132+
.FirstOrDefault(),
133+
Mobile = res.FieldDataList
134+
.Where(f => f.FieldCode == DingTalkConst.MobileField)
135+
.Select(f => f.FieldValueList.Select(v => v.Value).FirstOrDefault())
136+
.FirstOrDefault(),
137+
JobNumber = res.FieldDataList
138+
.Where(f => f.FieldCode == DingTalkConst.JobNumberField)
139+
.Select(f => f.FieldValueList.Select(v => v.Value).FirstOrDefault())
140+
.FirstOrDefault(),
141+
}).ToList();
142+
if (uUser.Count > 0)
143+
{
144+
var uUserRes = await _dingTalkUserRepo.CopyNew().AsUpdateable(uUser)
145+
.UpdateColumns(d => new
146+
{
147+
d.DingTalkUserId,
148+
d.Name,
149+
d.Mobile,
150+
d.JobNumber,
151+
d.UpdateTime,
152+
d.UpdateUserName,
153+
d.UpdateUserId,
154+
}).ExecuteCommandAsync();
155+
if (uUserRes <= 0)
156+
{
157+
throw Oops.Oh("更新钉钉用户错误");
158+
}
159+
}
160+
#endregion
161+
// 通过系统用户账号(工号),更新钉钉用户表里面的系统用户id
162+
var sysUser = await _sysUserRep.AsQueryable().Select(x => new
163+
{
164+
x.Id,
165+
x.Account
166+
}).ToListAsync();
167+
var sysDingTalkUser = await _dingTalkUserRepo.AsQueryable()
168+
.Where(d => sysUser.Any(u => u.Account == d.JobNumber))
169+
.Select(x => new
170+
{
171+
x.Id,
172+
x.JobNumber,
173+
x.Mobile
174+
}).ToListAsync();
175+
var uSysDingTalkUser = sysDingTalkUser.Select(d => new DingTalkUser
176+
{
177+
Id = d.Id,
178+
SysUserId = sysUser.Where(u => u.Account == d.JobNumber).Select(u => u.Id).FirstOrDefault(),
179+
}).ToList();
180+
var uSysDingTalkUserRes = await _dingTalkUserRepo.CopyNew().AsUpdateable(uSysDingTalkUser)
181+
.UpdateColumns(d => new
182+
{
183+
d.SysUserId,
184+
d.UpdateTime,
185+
d.UpdateUserName,
186+
d.UpdateUserId,
187+
}).ExecuteCommandAsync();
188+
if (uSysDingTalkUserRes <= 0)
189+
{
190+
_logger.LogError("同步钉钉用户错误");
191+
return;
192+
}
193+
var originColor = Console.ForegroundColor;
194+
Console.ForegroundColor = ConsoleColor.Yellow;
195+
Console.WriteLine("【" + DateTime.Now + "】同步钉钉用户");
196+
Console.ForegroundColor = originColor;
197+
}
198+
199+
}

Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/DingTalkService.cs

+7-133
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// 大名科技(天津)有限公司 版权所有
1+
// 大名科技(天津)有限公司 版权所有
22
//
33
// 此源代码遵循位于源代码树根目录中的 LICENSE 文件的许可证
44
//
@@ -31,144 +31,18 @@ public DingTalkService(IDingTalkApi dingTalkApi,
3131
}
3232

3333
/// <summary>
34-
/// 同步钉钉用户 🔖
34+
/// 获取企业内部应用的access_token
3535
/// </summary>
3636
/// <returns></returns>
37-
[DisplayName("同步钉钉用户")]
38-
public async Task SyncDingTalkUser()
37+
[DisplayName("获取企业内部应用的access_token")]
38+
public async Task<GetDingTalkTokenOutput> GetDingTalkToken()
3939
{
40-
var param = new GetDingTalkTokenInput()
41-
{
42-
AppKey = _dingTalkOptions.ClientId,
43-
AppSecret = _dingTalkOptions.ClientSecret
44-
};
45-
var tokenRes = await _dingTalkApi.GetDingTalkToken(param);
40+
var tokenRes = await _dingTalkApi.GetDingTalkToken(_dingTalkOptions.ClientId, _dingTalkOptions.ClientSecret);
4641
if (tokenRes.ErrCode != 0)
47-
throw Oops.Oh(tokenRes.ErrMsg);
48-
49-
var offset = 0;
50-
while (offset >= 0)
5142
{
52-
// 获取用户Id列表
53-
var userIdsRes = await _dingTalkApi.GetDingTalkCurrentEmployeesList(tokenRes.AccessToken, new GetDingTalkCurrentEmployeesListInput
54-
{
55-
StatusList = "2,3,5,-1",
56-
Size = 50,
57-
Offset = offset
58-
});
59-
if (!userIdsRes.Success)
60-
throw Oops.Oh(userIdsRes.ErrMsg);
61-
62-
// 根据用户Id获取花名册
63-
var rosterRes = await _dingTalkApi.GetDingTalkCurrentEmployeesRosterList(tokenRes.AccessToken, new GetDingTalkCurrentEmployeesRosterListInput()
64-
{
65-
UserIdList = string.Join(",", userIdsRes.Result.DataList),
66-
FieldFilterList = $"{DingTalkConst.NameField},{DingTalkConst.JobNumberField},{DingTalkConst.MobileField}",
67-
AgentId = _dingTalkOptions.AgentId
68-
});
69-
if (!rosterRes.Success)
70-
throw Oops.Oh(rosterRes.ErrMsg);
71-
72-
// 判断新增还是更新
73-
var userIds = rosterRes.Result.Select(u => u.UserId).ToList();
74-
var uDingTalkUser = await _dingTalkUserRepo.AsQueryable()
75-
.Where(u => userIds.Contains(u.DingTalkUserId))
76-
.ToListAsync();
77-
78-
var uUserIds = uDingTalkUser.Select(u => u.DingTalkUserId); // 需要更新的用户Id
79-
var iUserIds = userIds.Where(u => !uUserIds.Contains(u)); // 需要新增的用户Id
80-
81-
// 保存钉钉用户
82-
var iUsers = rosterRes.Result
83-
.Where(u => iUserIds.Contains(u.UserId))
84-
.Select(u => new DingTalkUser
85-
{
86-
DingTalkUserId = u.UserId,
87-
Name = u.FieldDataList.Where(m => m.FieldCode == DingTalkConst.NameField).Select(m => m.FieldValueList.Select(n => n.Value).FirstOrDefault()).FirstOrDefault(),
88-
Mobile = u.FieldDataList.Where(m => m.FieldCode == DingTalkConst.MobileField).Select(m => m.FieldValueList.Select(n => n.Value).FirstOrDefault()).FirstOrDefault(),
89-
JobNumber = u.FieldDataList.Where(m => m.FieldCode == DingTalkConst.JobNumberField).Select(m => m.FieldValueList.Select(n => n.Value).FirstOrDefault()).FirstOrDefault(),
90-
}).ToList();
91-
if (iUsers.Count > 0)
92-
{
93-
await _dingTalkUserRepo.AsInsertable(iUsers).ExecuteCommandAsync();
94-
}
95-
96-
// 更新钉钉用户
97-
var uUsers = rosterRes.Result
98-
.Where(u => uUserIds.Contains(u.UserId))
99-
.Select(u => new DingTalkUser
100-
{
101-
Id = uDingTalkUser.Where(m => m.DingTalkUserId == u.UserId).Select(m => m.Id).FirstOrDefault(),
102-
DingTalkUserId = u.UserId,
103-
Name = u.FieldDataList.Where(m => m.FieldCode == DingTalkConst.NameField).Select(m => m.FieldValueList.Select(n => n.Value).FirstOrDefault()).FirstOrDefault(),
104-
Mobile = u.FieldDataList.Where(m => m.FieldCode == DingTalkConst.MobileField).Select(m => m.FieldValueList.Select(n => n.Value).FirstOrDefault()).FirstOrDefault(),
105-
JobNumber = u.FieldDataList.Where(m => m.FieldCode == DingTalkConst.JobNumberField).Select(m => m.FieldValueList.Select(n => n.Value).FirstOrDefault()).FirstOrDefault(),
106-
}).ToList();
107-
if (uUsers.Count > 0)
108-
{
109-
await _dingTalkUserRepo.AsUpdateable(uUsers).UpdateColumns(u => new
110-
{
111-
u.DingTalkUserId,
112-
u.Name,
113-
u.Mobile,
114-
u.JobNumber,
115-
u.UpdateTime,
116-
u.UpdateUserName,
117-
u.UpdateUserId,
118-
}).ExecuteCommandAsync();
119-
}
120-
121-
// 保存分页游标
122-
if (userIdsRes.Result.NextCursor == null)
123-
break;
124-
offset = (int)userIdsRes.Result.NextCursor;
125-
}
126-
127-
var sysUser = await _sysUserRep.AsQueryable()
128-
.Select(u => new
129-
{
130-
u.Id,
131-
u.Account,
132-
u.Phone
133-
}).ToListAsync();
134-
var dingTalkUser = await _dingTalkUserRepo.AsQueryable()
135-
.Where(u => sysUser.Any(m => m.Account == u.JobNumber))
136-
.Select(u => new
137-
{
138-
u.Id,
139-
u.JobNumber,
140-
u.Mobile
141-
}).ToListAsync();
142-
143-
// 更新钉钉用户中系统用户Id
144-
var uDingTalkUsers = dingTalkUser.Select(u => new DingTalkUser
145-
{
146-
Id = u.Id,
147-
SysUserId = sysUser.Where(m => m.Account == u.JobNumber).Select(m => m.Id).FirstOrDefault(),
148-
}).ToList();
149-
if (uDingTalkUsers.Count > 0)
150-
{
151-
await _dingTalkUserRepo.AsUpdateable(uDingTalkUsers).UpdateColumns(u => new
152-
{
153-
u.SysUserId,
154-
u.UpdateTime,
155-
u.UpdateUserName,
156-
u.UpdateUserId,
157-
}).ExecuteCommandAsync();
43+
throw Oops.Oh(tokenRes.ErrMsg);
15844
}
159-
160-
return;
161-
}
162-
163-
/// <summary>
164-
/// 获取企业内部应用的access_token 🔖
165-
/// </summary>
166-
/// <param name="input"></param>
167-
/// <returns></returns>
168-
[DisplayName("获取企业内部应用的access_token")]
169-
public async Task<GetDingTalkTokenOutput> GetDingTalkToken([FromQuery] GetDingTalkTokenInput input)
170-
{
171-
return await _dingTalkApi.GetDingTalkToken(input);
45+
return tokenRes;
17246
}
17347

17448
/// <summary>

Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/GetDingTalkToken.cs

-12
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,6 @@
88

99
namespace Admin.NET.Plugin.DingTalk;
1010

11-
public class GetDingTalkTokenInput
12-
{
13-
/// <summary>
14-
/// 应用的唯一标识key
15-
/// </summary>
16-
public string AppKey { get; set; }
17-
18-
/// <summary>
19-
/// 应用的密钥。AppKey和AppSecret可在钉钉开发者后台的应用详情页面获取。
20-
/// </summary>
21-
public string AppSecret { get; set; }
22-
}
2311

2412
public class GetDingTalkTokenOutput
2513
{

0 commit comments

Comments
 (0)