Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation
This project
Loading...
Sign in
zhangshaowu
/
pipi-helper
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit 4a7e39e2
authored
Oct 15, 2022
by
weiss
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
1
1 parent
6bb6d59d
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
112 additions
and
858 deletions
src/main/java/com/pipihelper/project/feishu/controller/FeiShuEventController.java
src/main/java/com/pipihelper/project/feishu/controller/FeishuTaskController.java
src/main/java/com/pipihelper/project/controller/SendMsgUseFeiShu.java → src/main/java/com/pipihelper/project/feishu/controller/SendMsgUseFeiShu.java
src/main/java/com/pipihelper/project/feishu/dto/AppConfig.java
src/main/java/com/pipihelper/project/feishu/dto/FeiShuConfig.java
src/main/java/com/pipihelper/project/feishu/enums/CardElements.java
src/main/java/com/pipihelper/project/feishu/enums/ModuleType.java
src/main/java/com/pipihelper/project/feishu/enums/MsgCard.java
src/main/java/com/pipihelper/project/feishu/enums/NoticeType.java
src/main/java/com/pipihelper/project/feishu/enums/SendMsgBusinessType.java
src/main/java/com/pipihelper/project/feishu/service/FeiShuApiService.java
src/main/java/com/pipihelper/project/feishu/service/FeiShuEventService.java
src/main/java/com/pipihelper/project/feishu/service/anniversary/AbstractNoticeService.java
src/main/java/com/pipihelper/project/feishu/service/anniversary/AnniversaryNoticeService.java
src/main/java/com/pipihelper/project/feishu/service/anniversary/BirthdayNoticeService.java
src/main/java/com/pipihelper/project/feishu/service/anniversary/ConversionNoticeService.java
src/main/java/com/pipihelper/project/feishu/service/doc/DocHelperService.java
src/main/resources/application-dev.yml
src/main/java/com/pipihelper/project/feishu/controller/FeiShuEventController.java
View file @
4a7e39e
...
...
@@ -30,14 +30,14 @@ public class FeiShuEventController {
public
JSONObject
event
(
@RequestBody
String
s
)
throws
Exception
{
JSONObject
reqJsonObject
=
JSON
.
parseObject
(
s
);
System
.
out
.
println
(
s
);
FeiShuEventDataDecrypter
d
=
new
FeiShuEventDataDecrypter
(
feiShuConfig
.
get
AppConfigMap
().
get
(
feiShuConfig
.
getTestHelperApp
()).
get
EncryptKey
());
FeiShuEventDataDecrypter
d
=
new
FeiShuEventDataDecrypter
(
feiShuConfig
.
getEncryptKey
());
JSONObject
encryptJsonObject
=
JSON
.
parseObject
(
d
.
decrypt
(
reqJsonObject
.
getString
(
"encrypt"
)));
System
.
out
.
println
(
encryptJsonObject
);
if
(
encryptJsonObject
.
containsKey
(
"challenge"
))
{
return
encryptJsonObject
;
}
FeiShuEventDTO
feiShuEventDTO
=
encryptJsonObject
.
toJavaObject
(
FeiShuEventDTO
.
class
);
if
(!
feiShuEventDTO
.
getHeader
().
getToken
().
equalsIgnoreCase
(
feiShuConfig
.
get
AppConfigMap
().
get
(
feiShuConfig
.
getTestHelperApp
()).
get
VerificationToken
()))
{
if
(!
feiShuEventDTO
.
getHeader
().
getToken
().
equalsIgnoreCase
(
feiShuConfig
.
getVerificationToken
()))
{
return
null
;
}
if
(
"im.message.receive_v1"
.
equalsIgnoreCase
(
feiShuEventDTO
.
getHeader
().
getEvent_type
()))
{
...
...
src/main/java/com/pipihelper/project/feishu/controller/FeishuTaskController.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
controller
;
import
com.pipihelper.project.core.Result
;
import
com.pipihelper.project.core.ResultGenerator
;
import
com.pipihelper.project.feishu.service.doc.DocHelperService
;
import
com.pipihelper.project.feishu.vo.CreateTaskVo
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/**
* @author xiongjian
* @date 2022/7/27
*/
@RestController
@RequestMapping
(
"/pipitest"
)
@Slf4j
public
class
FeishuTaskController
{
@Autowired
private
DocHelperService
docHelperService
;
@RequestMapping
(
"/creatTask"
)
public
Result
creatTask
(
CreateTaskVo
createTaskVo
){
log
.
info
(
"创建任务接口:{}"
,
createTaskVo
);
docHelperService
.
createTask
(
createTaskVo
);
return
ResultGenerator
.
genSuccessResult
();
}
}
src/main/java/com/pipihelper/project/controller/SendMsgUseFeiShu.java
→
src/main/java/com/pipihelper/project/
feishu/
controller/SendMsgUseFeiShu.java
View file @
4a7e39e
package
com
.
pipihelper
.
project
.
controller
;
package
com
.
pipihelper
.
project
.
feishu
.
controller
;
import
com.alibaba.fastjson.JSONObject
;
import
com.pipihelper.project.core.Result
;
import
com.pipihelper.project.core.ResultGenerator
;
import
com.pipihelper.project.feishu.dto.FeiShuConfig
;
import
com.pipihelper.project.feishu.enums.SendMsgBusinessType
;
import
com.pipihelper.project.feishu.service.FeiShuApiService
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.PostMapping
;
...
...
@@ -36,7 +35,7 @@ public class SendMsgUseFeiShu {
content
.
put
(
"text"
,
msg
);
sendMsg
.
put
(
"content"
,
content
.
toString
());
feiShuApiService
.
sendMsg
(
SendMsgBusinessType
.
TALK
.
getBusinessType
(),
receiveIdType
,
sendMsg
,
feiShuConfig
.
getTestHelperApp
()
);
feiShuApiService
.
sendMsg
(
receiveIdType
,
sendMsg
);
return
ResultGenerator
.
genSuccessResult
();
}
}
src/main/java/com/pipihelper/project/feishu/dto/AppConfig.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
dto
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
@NoArgsConstructor
@Data
public
class
AppConfig
{
private
String
encryptKey
;
private
String
verificationToken
;
private
String
appId
;
private
String
appSecret
;
private
String
fkChatId
;
private
String
fkChatIdTest
;
private
String
tableId
;
private
String
peopleTableId
;
private
String
taskTableId
;
}
src/main/java/com/pipihelper/project/feishu/dto/FeiShuConfig.java
View file @
4a7e39e
...
...
@@ -21,10 +21,16 @@ import java.util.Map;
public
class
FeiShuConfig
{
private
String
feiShuOpenApiHost
;
private
String
testHelperApp
;
private
String
anniversaryApp
;
private
String
encryptKey
;
private
String
verificationToken
;
private
String
appId
;
private
String
appSecret
;
private
String
fkChatId
;
private
String
fkChatIdTest
;
private
Map
<
String
,
AppConfig
>
appConfigMap
;
private
String
tableId
;
private
String
peopleTableId
;
private
String
taskTableId
;
}
src/main/java/com/pipihelper/project/feishu/enums/CardElements.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
enums
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
import
java.util.ArrayList
;
import
java.util.List
;
@Getter
@AllArgsConstructor
public
enum
CardElements
{
APP_TYPE
(
"appType"
,
"select_static"
,
"APP类型"
),
MODULE
(
"module"
,
"select_static"
,
"业务场景"
),
LEVEL
(
"level"
,
"select_static"
,
"优先级"
),
ASSIGN
(
"assign"
,
"select_person"
,
"指派处理人"
),
VERIFY
(
"verify"
,
"select_person"
,
"转发给其他值班人"
),
HANDLE
(
"handle"
,
"button"
,
"我来"
),
FINISH_TIME
(
"finishTime"
,
"date_picker"
,
"预计完成时间"
),
FINISH
(
"finish"
,
"button"
,
"完成"
),
FILE_FINISH
(
"fileFinish"
,
"overflow"
,
"完成|完成并归档"
);
// FILED("button","","","");
private
String
action
;
private
String
tag
;
private
String
msg
;
}
src/main/java/com/pipihelper/project/feishu/enums/ModuleType.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
enums
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
@Getter
@AllArgsConstructor
public
enum
ModuleType
{
FRIENDS
(
1
,
"娱乐"
),
PLAY
(
2
,
"游戏"
),
MIDDLEWARE
(
3
,
"中台"
),
OTHER
(
4
,
"其他"
),
NONE
(
0
,
"未指定"
);
private
Integer
type
;
private
String
msg
;
public
static
Integer
getTypeByMsg
(
String
msg
)
{
for
(
ModuleType
moduleType
:
ModuleType
.
values
())
{
if
(
moduleType
.
getMsg
().
equals
(
msg
))
{
return
moduleType
.
getType
();
}
}
return
null
;
}
public
static
String
getMsgByType
(
Integer
type
)
{
for
(
ModuleType
moduleType
:
ModuleType
.
values
())
{
if
(
moduleType
.
getType
().
equals
(
type
))
{
return
moduleType
.
getMsg
();
}
}
return
null
;
}
}
src/main/java/com/pipihelper/project/feishu/enums/MsgCard.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
enums
;
import
com.pipihelper.project.core.ServiceException
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
@Getter
@AllArgsConstructor
public
enum
MsgCard
{
//CardElements.APP_TYPE, CardElements.MODULE, CardElements.LEVEL,CardElements.ASSIGN,CardElements.VERIFY, CardElements.HANDLE, CardElements.FINISH_TIME, CardElements.FINISH
TESTER_CARD_01
(
"tester_0"
,
Arrays
.
asList
(
CardElements
.
VERIFY
,
CardElements
.
HANDLE
),
"待值班确认"
,
1
),
TESTER_CARD_02
(
"tester_1"
,
Arrays
.
asList
(
CardElements
.
LEVEL
,
CardElements
.
ASSIGN
),
"待值班指派"
,
1
),
TESTER_CARD_03
(
"tester_2"
,
Arrays
.
asList
(
CardElements
.
FILE_FINISH
),
"负责人已完成待值班已确认"
,
1
),
//问题已完成,负责人未点完成,不允许测试点完成
TESTER_CARD_04
(
"tester_3"
,
Arrays
.
asList
(
CardElements
.
FINISH_TIME
,
CardElements
.
FILE_FINISH
),
"值班负责任务"
,
4
),
//负责人是自己的时候,可以点击填写完成时间
TESTER_CARD_05
(
"tester_4"
,
new
ArrayList
<>(),
"负责人已确认待解决"
,
4
),
//开发确认后,测试侧卡片
CODER_CARD_01
(
"coder_0"
,
Arrays
.
asList
(
CardElements
.
ASSIGN
,
CardElements
.
HANDLE
),
"待负责人确认"
,
1
),
CODER_CARD_02
(
"coder_1"
,
Arrays
.
asList
(
CardElements
.
FINISH_TIME
,
CardElements
.
FINISH
),
"负责人已确认待解决"
,
4
),
//负责人只能完成,不能归档
FILE
(
"file"
,
new
ArrayList
<>(),
"卡片固化"
,
null
);
private
String
type
;
private
List
<
CardElements
>
elements
;
private
String
msg
;
private
Integer
interval
;
public
static
List
<
CardElements
>
getElementsByType
(
String
type
)
{
for
(
MsgCard
msgCard
:
MsgCard
.
values
())
{
if
(
msgCard
.
getType
().
equals
(
type
))
{
return
msgCard
.
getElements
();
}
}
throw
new
ServiceException
(
"类型不匹配"
);
}
public
static
Integer
getIntervalByType
(
String
type
)
{
for
(
MsgCard
msgCard
:
MsgCard
.
values
())
{
if
(
msgCard
.
getType
().
equals
(
type
))
{
return
msgCard
.
getInterval
();
}
}
throw
new
ServiceException
(
"类型不匹配"
);
}
}
src/main/java/com/pipihelper/project/feishu/enums/NoticeType.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
enums
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
/**
* @Description: TODO
* @author: charles
* @date: 2022年06月08日 14:21
*/
@Getter
@AllArgsConstructor
public
enum
NoticeType
{
NONE
(
0
,
"未发送提醒"
),
URGENT_APP
(
1
,
"app内加急"
),
URGENT_SMS
(
2
,
"短信加急"
),
URGENT_PHONE
(
3
,
"电话加急"
),
URGENT_APP_24
(
4
,
"app内加急"
),
URGENT_SMS_24
(
5
,
"短信加急"
),
URGENT_PHONE_24
(
6
,
"电话加急"
);
private
Integer
type
;
private
String
msg
;
}
src/main/java/com/pipihelper/project/feishu/enums/SendMsgBusinessType.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
enums
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
@Getter
@AllArgsConstructor
public
enum
SendMsgBusinessType
{
/***
* 机器人发送消息的消息类型
*/
FEEDBACKS
(
0
,
"反馈群反馈问题"
),
FEEDBACKS_DATA
(
1
,
""
),
TALK
(
2
,
"一般性对话"
),
DUTY_NOTICE
(
3
,
"值班提醒"
),
HAR
(
4
,
"解析har文件"
),
SYNC_DICT
(
5
,
"同步字典"
),
TEST_DATA
(
6
,
"处理测试数据"
),
DEFAULT
(-
1
,
""
);
private
Integer
businessType
;
private
String
description
;
}
src/main/java/com/pipihelper/project/feishu/service/FeiShuApiService.java
View file @
4a7e39e
...
...
@@ -64,16 +64,16 @@ public class FeiShuApiService {
.
expireAfterWrite
(
Duration
.
ofHours
(
2
))
.
build
();
public
String
getTenantToken
(
String
appName
)
{
return
FEISHU_CACHE
.
get
(
"tenantAccessToken"
+
appName
,
key
->
setTenantAccessToken
(
appName
));
public
String
getTenantToken
()
{
return
FEISHU_CACHE
.
get
(
"tenantAccessToken"
,
key
->
setTenantAccessToken
(
));
}
public
String
setTenantAccessToken
(
String
appName
)
{
public
String
setTenantAccessToken
()
{
String
api
=
"/auth/v3/tenant_access_token/internal"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
JSONObject
params
=
new
JSONObject
();
params
.
put
(
"app_id"
,
feiShuConfig
.
getApp
ConfigMap
().
get
(
appName
).
getApp
Id
());
params
.
put
(
"app_secret"
,
feiShuConfig
.
getApp
ConfigMap
().
get
(
appName
).
getApp
Secret
());
params
.
put
(
"app_id"
,
feiShuConfig
.
getAppId
());
params
.
put
(
"app_secret"
,
feiShuConfig
.
getAppSecret
());
ResponseEntity
<
JSONObject
>
responseEntity
=
restTemplate
.
postForEntity
(
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
,
params
,
JSONObject
.
class
);
System
.
out
.
println
(
responseEntity
.
getBody
().
get
(
"tenant_access_token"
).
toString
());
return
responseEntity
.
getBody
().
get
(
"tenant_access_token"
).
toString
();
...
...
@@ -84,14 +84,14 @@ public class FeiShuApiService {
* @param sendMsg
* @return
*/
public
JSONObject
sendMsg
(
Integer
businessType
,
String
receive_id_type
,
JSONObject
sendMsg
,
String
appName
)
{
public
JSONObject
sendMsg
(
String
receive_id_type
,
JSONObject
sendMsg
)
{
System
.
out
.
println
(
sendMsg
.
toString
());
//发送消息
String
api
=
"/im/v1/messages?receive_id_type={receive_id_type}"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
sendMsg
.
toString
(),
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -100,7 +100,7 @@ public class FeiShuApiService {
if
(
responseEntity
.
getBody
().
getJSONObject
(
"data"
)
==
null
)
{
return
null
;
}
log
.
info
(
"
业务类型:{} ,消息发送成功,接收人: {}"
,
businessType
,
sendMsg
.
getString
(
"receive_id"
));
log
.
info
(
"
消息发送成功,接收人: {}"
,
sendMsg
.
getString
(
"receive_id"
));
return
responseEntity
.
getBody
();
}
catch
(
Exception
e
)
{
log
.
error
(
"飞书:"
+
api
+
"接口调用失败"
+
"\n"
+
e
);
...
...
@@ -111,12 +111,12 @@ public class FeiShuApiService {
@Async
public
JSONObject
replyMsg
(
String
message_id
,
JSONObject
replyMsg
,
String
appName
)
{
public
JSONObject
replyMsg
(
String
message_id
,
JSONObject
replyMsg
)
{
System
.
out
.
println
(
replyMsg
.
toString
());
String
api
=
"/im/v1/messages/{message_id}/reply"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
replyMsg
.
toString
(),
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -130,7 +130,7 @@ public class FeiShuApiService {
}
@Async
public
JSONObject
patchMsg
(
String
message_id
,
JSONObject
content
,
String
appName
)
{
public
JSONObject
patchMsg
(
String
message_id
,
JSONObject
content
)
{
String
api
=
"/im/v1/messages/"
;
OkHttpClient
client
=
new
OkHttpClient
();
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -138,7 +138,7 @@ public class FeiShuApiService {
Request
request
=
new
Request
.
Builder
()
.
patch
(
requestBody
)
.
url
(
url
+
message_id
)
.
addHeader
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
))
.
addHeader
(
"Authorization"
,
"Bearer "
+
getTenantToken
())
.
addHeader
(
"Content-Type"
,
"application/json; charset=utf-8"
)
.
build
();
try
{
...
...
@@ -152,7 +152,7 @@ public class FeiShuApiService {
}
@Async
public
JSONObject
patchUrgentApp
(
String
message_id
,
JSONObject
content
,
String
appName
)
{
public
JSONObject
patchUrgentApp
(
String
message_id
,
JSONObject
content
)
{
String
api
=
"/im/v1/messages/"
+
message_id
+
"/urgent_sms?user_id_type=open_id"
;
OkHttpClient
client
=
new
OkHttpClient
();
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -160,7 +160,7 @@ public class FeiShuApiService {
Request
request
=
new
Request
.
Builder
()
.
patch
(
requestBody
)
.
url
(
url
)
.
addHeader
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
))
.
addHeader
(
"Authorization"
,
"Bearer "
+
getTenantToken
())
.
addHeader
(
"Content-Type"
,
"application/json; charset=utf-8"
)
.
build
();
try
{
...
...
@@ -176,7 +176,7 @@ public class FeiShuApiService {
@Async
public
JSONObject
patchUrgentSms
(
String
message_id
,
JSONObject
content
,
String
appName
)
{
public
JSONObject
patchUrgentSms
(
String
message_id
,
JSONObject
content
)
{
String
api
=
"/im/v1/messages/"
+
message_id
+
"/urgent_app?user_id_type=open_id"
;
OkHttpClient
client
=
new
OkHttpClient
();
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -184,7 +184,7 @@ public class FeiShuApiService {
Request
request
=
new
Request
.
Builder
()
.
patch
(
requestBody
)
.
url
(
url
)
.
addHeader
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
))
.
addHeader
(
"Authorization"
,
"Bearer "
+
getTenantToken
())
.
addHeader
(
"Content-Type"
,
"application/json; charset=utf-8"
)
.
build
();
try
{
...
...
@@ -200,12 +200,12 @@ public class FeiShuApiService {
// @Async
public
String
createTask
(
FeiShuCreateTaskDTO
taskMsg
,
String
openId
,
String
appName
)
{
public
String
createTask
(
FeiShuCreateTaskDTO
taskMsg
,
String
openId
)
{
log
.
info
(
"调用创建任务接口,task: {}"
,
taskMsg
.
toString
());
String
api
=
"/task/v1/tasks"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
// headers.set("Authorization", "Bearer " + "t-d3db00058d854b3c004ffdf6453fd3e169c82043");
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
...
...
@@ -215,7 +215,7 @@ public class FeiShuApiService {
try
{
ResponseEntity
<
JSONObject
>
responseEntity
=
restTemplate
.
postForEntity
(
url
,
requestEntity
,
JSONObject
.
class
);
String
taskId
=
responseEntity
.
getBody
().
getJSONObject
(
"data"
).
getJSONObject
(
"task"
).
getString
(
"id"
);
collaborators
(
taskId
,
openId
,
appName
);
collaborators
(
taskId
,
openId
);
return
taskId
;
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"飞书:"
+
api
+
"接口调用失败"
+
"\n"
+
e
);
...
...
@@ -223,7 +223,7 @@ public class FeiShuApiService {
}
public
JSONObject
collaborators
(
String
taskId
,
String
openId
,
String
appName
)
{
public
JSONObject
collaborators
(
String
taskId
,
String
openId
)
{
if
(
StringUtils
.
isBlank
(
openId
))
{
return
null
;
}
...
...
@@ -232,7 +232,7 @@ public class FeiShuApiService {
JSONObject
param
=
new
JSONObject
();
param
.
put
(
"id"
,
openId
);
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
param
.
toString
(),
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -245,11 +245,11 @@ public class FeiShuApiService {
}
public
byte
[]
getMessageFile
(
String
messageId
,
String
fileKey
,
String
type
,
String
appName
)
{
public
byte
[]
getMessageFile
(
String
messageId
,
String
fileKey
,
String
type
)
{
String
api
=
"/im/v1/messages/{messageId}/resources/{fileKey}/?type={type}"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
HttpEntity
<
MultiValueMap
<
String
,
Object
>>
requestEntity
=
new
HttpEntity
<>(
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
try
{
...
...
@@ -261,11 +261,11 @@ public class FeiShuApiService {
}
//获取指定部门下的员工信息
public
JSONObject
getUser
(
String
department_id
,
String
appName
)
{
public
JSONObject
getUser
(
String
department_id
)
{
String
api
=
"/contact/v3/users/find_by_department?department_id={department_id}"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -278,11 +278,11 @@ public class FeiShuApiService {
}
//下载文件
public
byte
[]
downloadFile
(
String
filePath
,
String
appName
)
{
public
byte
[]
downloadFile
(
String
filePath
)
{
String
api
=
"/im/v1/files/{filePath}"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
try
{
...
...
@@ -294,11 +294,11 @@ public class FeiShuApiService {
}
//上传文件
public
String
uploadFile
(
String
file_type
,
String
file_name
,
Integer
duration
,
byte
[]
file
,
String
appName
)
{
public
String
uploadFile
(
String
file_type
,
String
file_name
,
Integer
duration
,
byte
[]
file
)
{
String
api
=
"/im/v1/files"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
setContentType
(
org
.
springframework
.
http
.
MediaType
.
MULTIPART_FORM_DATA
);
MultiValueMap
<
String
,
Object
>
param
=
new
LinkedMultiValueMap
<>();
param
.
add
(
"file_type"
,
file_type
);
...
...
@@ -316,11 +316,11 @@ public class FeiShuApiService {
}
//获取应用有权限的所有部门
public
JSONObject
getDepartment
(
String
appName
)
{
public
JSONObject
getDepartment
()
{
String
api
=
"/contact/v3/departments?fetch_child=true"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -338,15 +338,15 @@ public class FeiShuApiService {
*
* @return
*/
public
List
<
FeiShuEmployeeDTO
>
getEmployeeList
(
String
appName
)
{
return
EMPLOYEE_LIST_CACHE
.
get
(
"employeeList"
,
s
->
setEmployeeList
(
appName
));
public
List
<
FeiShuEmployeeDTO
>
getEmployeeList
()
{
return
EMPLOYEE_LIST_CACHE
.
get
(
"employeeList"
,
s
->
setEmployeeList
());
}
private
List
<
FeiShuEmployeeDTO
>
setEmployeeList
(
String
appName
)
{
private
List
<
FeiShuEmployeeDTO
>
setEmployeeList
()
{
String
api
=
"/ehr/v1/employees?view=full&status=2&status=4&page_size=100"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -375,11 +375,11 @@ public class FeiShuApiService {
*
* @return
*/
public
List
<
FeiShuChatDTO
>
getChatList
(
String
appName
)
{
public
List
<
FeiShuChatDTO
>
getChatList
()
{
String
api
=
"/im/v1/chats"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -399,12 +399,12 @@ public class FeiShuApiService {
* 群发消息
* https://open.feishu.cn/document/ukTMukTMukTM/ucDO1EjL3gTNx4yN4UTM
*/
public
void
sendBatchMsg
(
FeiShuBatchMsgDTO
feiShuBatchMsgDTO
,
String
appName
)
{
public
void
sendBatchMsg
(
FeiShuBatchMsgDTO
feiShuBatchMsgDTO
)
{
String
api
=
"/message/v4/batch_send/"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
try
{
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
objectMapper
.
writeValueAsString
(
feiShuBatchMsgDTO
),
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -422,12 +422,12 @@ public class FeiShuApiService {
*
* @param feiShuMsgDTO
*/
public
void
sendMsg
(
FeiShuMsgDTO
feiShuMsgDTO
,
String
receiveIdType
,
String
appName
)
{
public
void
sendMsg
(
FeiShuMsgDTO
feiShuMsgDTO
,
String
receiveIdType
)
{
String
api
=
"/im/v1/messages?receive_id_type={receiveIdType}"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
try
{
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
objectMapper
.
writeValueAsString
(
feiShuMsgDTO
),
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -446,11 +446,11 @@ public class FeiShuApiService {
* @param departmentId
* @return
*/
public
FeiShuDepartmentDTO
getDepartment
(
String
departmentId
,
String
appName
)
{
public
FeiShuDepartmentDTO
getDepartment
(
String
departmentId
)
{
String
api
=
"/contact/v3/departments/{departmentId}"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -471,14 +471,14 @@ public class FeiShuApiService {
*
* @param appToken
* @param tableId
* @param appName
* @return
*/
public
List
getTableRecords
(
String
appToken
,
String
tableId
,
String
appName
)
{
public
List
getTableRecords
(
String
appToken
,
String
tableId
)
{
String
api
=
"/bitable/v1/apps/{app_token}/tables/{table_id}/records"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
...
...
@@ -508,15 +508,14 @@ public class FeiShuApiService {
* @param appToken
* @param tableId
* @param recordId
* @param appName
* @param docDTO
* @return
*/
public
FeiShuResultDTO
updateTableRecords
(
String
appToken
,
String
tableId
,
String
recordId
,
String
appName
,
DocDTO
docDTO
)
{
public
FeiShuResultDTO
updateTableRecords
(
String
appToken
,
String
tableId
,
String
recordId
,
DocDTO
docDTO
)
{
String
api
=
"/bitable/v1/apps/{app_token}/tables/{table_id}/records/{record_id}"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
(
appName
));
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
JSONObject
.
toJSONString
(
docDTO
),
headers
);
...
...
@@ -530,4 +529,53 @@ public class FeiShuApiService {
}
}
//获取主日历
public
JSONObject
calendars
()
{
//查询主日历,获取日历id
String
api
=
"/calendar/v4/calendars/primary?user_id_type=open_id"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
try
{
ResponseEntity
<
JSONObject
>
responseEntity
=
restTemplate
.
postForEntity
(
url
,
requestEntity
,
JSONObject
.
class
);
return
responseEntity
.
getBody
();
}
catch
(
Exception
e
)
{
log
.
error
(
"飞书:"
+
api
+
"接口调用失败"
+
"\n"
+
e
);
throw
new
ServiceException
(
"飞书:"
+
api
+
"接口调用失败"
+
"\n"
+
e
);
}
}
//获取会议室列表
public
List
<
FeiShuEmployeeDTO
>
getMeetingRooms
()
{
String
api
=
"/ehr/v1/employees?view=full&status=2&status=4&page_size=100"
;
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
set
(
"Authorization"
,
"Bearer "
+
getTenantToken
());
headers
.
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
HttpEntity
<
String
>
requestEntity
=
new
HttpEntity
<>(
headers
);
String
url
=
feiShuConfig
.
getFeiShuOpenApiHost
()
+
api
;
try
{
ResponseEntity
<
String
>
responseEntity
=
restTemplate
.
exchange
(
url
,
HttpMethod
.
GET
,
requestEntity
,
String
.
class
);
Type
type
=
new
TypeReference
<
FeiShuResultDTO
<
FeiShuEmployeeDTO
>>()
{
}.
getType
();
FeiShuResultDTO
feiShuResultDTO
=
JSONObject
.
parseObject
(
responseEntity
.
getBody
(),
type
);
List
<
FeiShuEmployeeDTO
>
feiShuEmployeeDTOList
=
new
ArrayList
<>();
feiShuEmployeeDTOList
.
addAll
(
feiShuResultDTO
.
getData
().
getItems
());
while
(
feiShuResultDTO
.
getData
().
getItems
().
size
()
>=
100
)
{
ResponseEntity
<
String
>
next
=
restTemplate
.
exchange
(
url
+
"&page_token="
+
feiShuResultDTO
.
getData
().
getPageToken
(),
HttpMethod
.
GET
,
requestEntity
,
String
.
class
);
feiShuResultDTO
=
JSONObject
.
parseObject
(
next
.
getBody
(),
type
);
feiShuEmployeeDTOList
.
addAll
(
feiShuResultDTO
.
getData
().
getItems
());
}
log
.
info
(
"花名册获取完成,总计 {} 人"
,
feiShuEmployeeDTOList
.
size
());
return
feiShuEmployeeDTOList
;
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"飞书:"
+
api
+
"接口调用失败"
+
"\n"
+
e
);
}
}
}
src/main/java/com/pipihelper/project/feishu/service/FeiShuEventService.java
View file @
4a7e39e
...
...
@@ -46,8 +46,8 @@ public class FeiShuEventService {
FeiShuEventReceiveMessageDTO
.
Sender
sender
=
feiShuEventReceiveMessageDTO
.
getSender
();
FeiShuEventReceiveMessageDTO
.
Message
message
=
feiShuEventReceiveMessageDTO
.
getMessage
();
//单独处理群消息
if
(
message
.
getChat_id
().
equals
(
feiShuConfig
.
get
AppConfigMap
().
get
(
feiShuConfig
.
getTestHelperApp
()).
get
FkChatId
())
||
message
.
getChat_id
().
equals
(
feiShuConfig
.
get
AppConfigMap
().
get
(
feiShuConfig
.
getTestHelperApp
()).
get
FkChatIdTest
()))
{
//判断是否为指定群消息
if
(
message
.
getChat_id
().
equals
(
feiShuConfig
.
getFkChatId
())
||
message
.
getChat_id
().
equals
(
feiShuConfig
.
getFkChatIdTest
()))
{
//判断是否为指定群消息
return
;
}
else
{
...
...
src/main/java/com/pipihelper/project/feishu/service/anniversary/AbstractNoticeService.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
service
.
anniversary
;
import
com.pipihelper.project.feishu.dto.FeiShuConfig
;
import
com.pipihelper.project.feishu.dto.department.FeiShuDepartmentDTO
;
import
com.pipihelper.project.feishu.dto.employee.FeiShuEmployeeDTO
;
import
com.pipihelper.project.feishu.dto.msg.FeiShuMsgDTO
;
import
com.pipihelper.project.feishu.service.FeiShuApiService
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.Resource
;
import
java.io.BufferedReader
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
@Service
public
abstract
class
AbstractNoticeService
{
@Resource
private
FeiShuConfig
feiShuConfig
;
@Autowired
private
FeiShuApiService
feiShuApiService
;
/**
* 发送通知
*/
public
abstract
void
notice
();
/**
* 生成员工消息卡片
* @param feiShuEmployeeDTO
* @return
*/
public
abstract
FeiShuMsgDTO
generateEmployeeMsgCard
(
FeiShuEmployeeDTO
feiShuEmployeeDTO
);
/**
* 生产领导消息卡片
* @param feiShuEmployeeDTO
* @return
*/
public
abstract
FeiShuMsgDTO
generateLeaderMsgCard
(
FeiShuEmployeeDTO
feiShuEmployeeDTO
);
/**
* 获取领导OpenId
*
* @param departmentId
* @return
*/
public
String
getLeaderOpenId
(
String
departmentId
)
{
if
(
StringUtils
.
isBlank
(
departmentId
))
{
return
""
;
}
if
(
"0"
.
equals
(
departmentId
))
{
// 若递归无上级负责人,则获取企业创建人
return
feiShuApiService
.
getUser
(
"0"
,
feiShuConfig
.
getAnniversaryApp
()).
getJSONObject
(
"data"
).
getJSONArray
(
"items"
).
getJSONObject
(
0
).
getString
(
"open_id"
);
}
FeiShuDepartmentDTO
feiShuDepartmentDTO
=
feiShuApiService
.
getDepartment
(
departmentId
,
feiShuConfig
.
getAnniversaryApp
());
return
StringUtils
.
isNotBlank
(
feiShuDepartmentDTO
.
getLeaderUserId
())
?
feiShuDepartmentDTO
.
getLeaderUserId
()
:
getLeaderOpenId
(
feiShuDepartmentDTO
.
getParentDepartmentId
());
}
/**
* 给部门领导发送消息,若领导是自己,则找父部门领导
*
* @param feiShuMsgDTO
* @param feiShuEmployeeDTO
*/
public
void
sendMsgToLeader
(
FeiShuMsgDTO
feiShuMsgDTO
,
FeiShuEmployeeDTO
feiShuEmployeeDTO
)
{
String
leaderOpenId
=
getLeaderOpenId
(
feiShuEmployeeDTO
.
getSystemFields
().
getDepartmentId
());
// 领导是自己,找父部门领导
if
(
leaderOpenId
.
equals
(
feiShuEmployeeDTO
.
getUserId
())
&&
!
"0"
.
equals
(
feiShuEmployeeDTO
.
getSystemFields
().
getDepartmentId
()))
{
leaderOpenId
=
getLeaderOpenId
(
feiShuApiService
.
getDepartment
(
feiShuEmployeeDTO
.
getSystemFields
().
getDepartmentId
(),
feiShuConfig
.
getAnniversaryApp
()).
getParentDepartmentId
());
}
if
(!
leaderOpenId
.
equals
(
feiShuEmployeeDTO
.
getUserId
())
&&
StringUtils
.
isNotBlank
(
leaderOpenId
))
{
// 给领导发送消息
feiShuMsgDTO
.
setReceiveId
(
leaderOpenId
);
feiShuApiService
.
sendMsg
(
feiShuMsgDTO
,
"open_id"
,
feiShuConfig
.
getAnniversaryApp
());
}
}
/**
* 读取模板文件
* @param file
* @return
*/
public
String
getInteractiveCardStr
(
String
file
){
try
{
InputStream
in
=
this
.
getClass
().
getResourceAsStream
(
file
);
InputStreamReader
inputStreamReader
=
new
InputStreamReader
(
in
);
Stream
<
String
>
streamOfString
=
new
BufferedReader
(
inputStreamReader
).
lines
();
String
streamToString
=
streamOfString
.
collect
(
Collectors
.
joining
());
return
streamToString
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
return
""
;
}
}
src/main/java/com/pipihelper/project/feishu/service/anniversary/AnniversaryNoticeService.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
service
.
anniversary
;
import
com.pipihelper.project.feishu.dto.FeiShuConfig
;
import
com.pipihelper.project.feishu.dto.employee.FeiShuEmployeeDTO
;
import
com.pipihelper.project.feishu.dto.msg.FeiShuMsgDTO
;
import
com.pipihelper.project.feishu.service.FeiShuApiService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.Resource
;
import
java.time.LocalDate
;
import
java.util.List
;
import
java.util.stream.Collectors
;
/**
* 飞书入职周年提醒
*/
@Service
@Slf4j
public
class
AnniversaryNoticeService
extends
AbstractNoticeService
{
@Autowired
private
FeiShuApiService
feiShuApiService
;
@Resource
private
FeiShuConfig
feiShuConfig
;
@Override
public
void
notice
()
{
// 1. 获取当天生日人
List
<
FeiShuEmployeeDTO
>
feiShuEmployeeDTOList
=
feiShuApiService
.
getEmployeeList
(
feiShuConfig
.
getAnniversaryApp
());
List
<
FeiShuEmployeeDTO
>
hireDayEmployees
=
feiShuEmployeeDTOList
.
stream
()
.
filter
(
feiShuEmployeeDTO
->
StringUtils
.
isNotEmpty
(
feiShuEmployeeDTO
.
getSystemFields
().
getHireDate
()))
.
filter
(
feiShuEmployeeDTO
->
{
LocalDate
hireDay
=
LocalDate
.
parse
(
feiShuEmployeeDTO
.
getSystemFields
().
getHireDate
());
// 使用plusYears可以避免2月29日的特殊情况.当年若无2月29日,生日则为2月28日
long
years
=
LocalDate
.
now
().
getYear
()
-
hireDay
.
getYear
();
// 1,2,3,5周年时发送提醒
return
hireDay
.
plusYears
(
years
).
equals
(
LocalDate
.
now
())
&&
(
years
==
1
||
years
==
2
||
years
==
3
||
years
==
5
);
})
.
peek
(
feiShuEmployeeDTO
->
{
// 给员工自己发消息
feiShuApiService
.
sendMsg
(
generateEmployeeMsgCard
(
feiShuEmployeeDTO
),
"open_id"
,
feiShuConfig
.
getAnniversaryApp
());
// 给领导发送消息
sendMsgToLeader
(
generateLeaderMsgCard
(
feiShuEmployeeDTO
),
feiShuEmployeeDTO
);
}).
collect
(
Collectors
.
toList
());
log
.
info
(
"{} 当日周年人: {}"
,
LocalDate
.
now
(),
hireDayEmployees
);
}
@Override
public
FeiShuMsgDTO
generateEmployeeMsgCard
(
FeiShuEmployeeDTO
feiShuEmployeeDTO
)
{
LocalDate
hireDay
=
LocalDate
.
parse
(
feiShuEmployeeDTO
.
getSystemFields
().
getHireDate
());
long
years
=
LocalDate
.
now
().
getYear
()
-
hireDay
.
getYear
();
String
fileName
=
String
.
format
(
"/templates/anniversary-employee-%s.json"
,
years
);
FeiShuMsgDTO
feiShuMsgDTO
=
new
FeiShuMsgDTO
();
feiShuMsgDTO
.
setMsgType
(
"interactive"
);
feiShuMsgDTO
.
setContent
(
String
.
format
(
getInteractiveCardStr
(
fileName
),
feiShuEmployeeDTO
.
getSystemFields
().
getName
()));
feiShuMsgDTO
.
setReceiveId
(
feiShuEmployeeDTO
.
getUserId
());
return
feiShuMsgDTO
;
}
@Override
public
FeiShuMsgDTO
generateLeaderMsgCard
(
FeiShuEmployeeDTO
feiShuEmployeeDTO
)
{
LocalDate
hireDay
=
LocalDate
.
parse
(
feiShuEmployeeDTO
.
getSystemFields
().
getHireDate
());
long
years
=
LocalDate
.
now
().
getYear
()
-
hireDay
.
getYear
();
String
fileName
=
String
.
format
(
"/templates/anniversary-leader-%s.json"
,
String
.
valueOf
(
years
));
FeiShuMsgDTO
feiShuMsgDTO
=
new
FeiShuMsgDTO
();
feiShuMsgDTO
.
setMsgType
(
"interactive"
);
feiShuMsgDTO
.
setContent
(
String
.
format
(
getInteractiveCardStr
(
fileName
),
feiShuEmployeeDTO
.
getSystemFields
().
getName
()));
return
feiShuMsgDTO
;
}
}
src/main/java/com/pipihelper/project/feishu/service/anniversary/BirthdayNoticeService.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
service
.
anniversary
;
import
com.pipihelper.project.feishu.dto.FeiShuConfig
;
import
com.pipihelper.project.feishu.dto.msg.FeiShuMsgDTO
;
import
com.pipihelper.project.feishu.dto.employee.FeiShuEmployeeDTO
;
import
com.pipihelper.project.feishu.service.FeiShuApiService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.Resource
;
import
java.time.LocalDate
;
import
java.util.List
;
import
java.util.stream.Collectors
;
/**
* 飞书生日提醒
*/
@Service
@Slf4j
public
class
BirthdayNoticeService
extends
AbstractNoticeService
{
@Autowired
private
FeiShuApiService
feiShuApiService
;
@Resource
private
FeiShuConfig
feiShuConfig
;
@Override
public
void
notice
()
{
// 1. 获取当天生日人
List
<
FeiShuEmployeeDTO
>
feiShuEmployeeDTOList
=
feiShuApiService
.
getEmployeeList
(
feiShuConfig
.
getAnniversaryApp
());
List
<
FeiShuEmployeeDTO
>
birthdayEmployees
=
feiShuEmployeeDTOList
.
stream
()
.
filter
(
feiShuEmployeeDTO
->
StringUtils
.
isNotEmpty
(
feiShuEmployeeDTO
.
getSystemFields
().
getBirthday
()))
.
filter
(
feiShuEmployeeDTO
->
{
LocalDate
birthday
=
LocalDate
.
parse
(
feiShuEmployeeDTO
.
getSystemFields
().
getBirthday
());
// 使用plusYears可以避免2月29日的特殊情况.当年若无2月29日,生日则为2月28日
long
years
=
LocalDate
.
now
().
getYear
()
-
birthday
.
getYear
();
return
birthday
.
plusYears
(
years
).
equals
(
LocalDate
.
now
());
})
.
map
(
feiShuEmployeeDTO
->
{
// 给员工自己发消息
feiShuApiService
.
sendMsg
(
generateEmployeeMsgCard
(
feiShuEmployeeDTO
),
"open_id"
,
feiShuConfig
.
getAnniversaryApp
());
// 给领导发送消息
sendMsgToLeader
(
generateLeaderMsgCard
(
feiShuEmployeeDTO
),
feiShuEmployeeDTO
);
return
feiShuEmployeeDTO
;
}).
collect
(
Collectors
.
toList
());
log
.
info
(
"{} 当日生日人: {}"
,
LocalDate
.
now
(),
birthdayEmployees
);
}
@Override
public
FeiShuMsgDTO
generateEmployeeMsgCard
(
FeiShuEmployeeDTO
feiShuEmployeeDTO
)
{
FeiShuMsgDTO
feiShuMsgDTO
=
new
FeiShuMsgDTO
();
feiShuMsgDTO
.
setMsgType
(
"interactive"
);
feiShuMsgDTO
.
setContent
(
String
.
format
(
getInteractiveCardStr
(
"/templates/birthday-employee.json"
),
feiShuEmployeeDTO
.
getSystemFields
().
getName
()));
feiShuMsgDTO
.
setReceiveId
(
feiShuEmployeeDTO
.
getUserId
());
return
feiShuMsgDTO
;
}
@Override
public
FeiShuMsgDTO
generateLeaderMsgCard
(
FeiShuEmployeeDTO
feiShuEmployeeDTO
)
{
FeiShuMsgDTO
feiShuMsgDTO
=
new
FeiShuMsgDTO
();
feiShuMsgDTO
.
setMsgType
(
"interactive"
);
feiShuMsgDTO
.
setContent
(
String
.
format
(
getInteractiveCardStr
(
"/templates/birthday-leader.json"
),
feiShuEmployeeDTO
.
getSystemFields
().
getName
()));
return
feiShuMsgDTO
;
}
}
src/main/java/com/pipihelper/project/feishu/service/anniversary/ConversionNoticeService.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
service
.
anniversary
;
import
com.pipihelper.project.feishu.dto.FeiShuConfig
;
import
com.pipihelper.project.feishu.dto.msg.FeiShuMsgDTO
;
import
com.pipihelper.project.feishu.dto.employee.FeiShuEmployeeDTO
;
import
com.pipihelper.project.feishu.service.FeiShuApiService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.Resource
;
import
java.time.LocalDate
;
import
java.util.List
;
import
java.util.stream.Collectors
;
/**
* 飞书转正日提醒
*/
@Service
@Slf4j
public
class
ConversionNoticeService
extends
AbstractNoticeService
{
@Autowired
private
FeiShuApiService
feiShuApiService
;
@Resource
private
FeiShuConfig
feiShuConfig
;
/**
* 逻辑来自HR
* 转正日为入职日过6个月
* 一般是入职是X月Y日,那么6个月是到X+6月Y-1日到期,第二天的X+6月Y日是转正的第一天了
* 特殊情况就是有一些月份的30日 31日入职,那么转正月份因为当月最后1天不是30号或者31号,那么我们就按照当月的最后1天作为转正日
* 最典型的就是8月31日入职,转正日期可能是2月28日,也可能是2月29日
* 或者12月31日入职,那么转正日期是6月30日(因为6月没有31号);但是1月31日入职,转正日期就是7月31日(因为7月最后1天就是31号)
*/
@Override
public
void
notice
()
{
// 1. 获取当天生日人
List
<
FeiShuEmployeeDTO
>
feiShuEmployeeDTOList
=
feiShuApiService
.
getEmployeeList
(
feiShuConfig
.
getAnniversaryApp
());
List
<
FeiShuEmployeeDTO
>
hireDayEmployees
=
feiShuEmployeeDTOList
.
stream
()
.
filter
(
feiShuEmployeeDTO
->
StringUtils
.
isNotEmpty
(
feiShuEmployeeDTO
.
getSystemFields
().
getHireDate
()))
.
filter
(
feiShuEmployeeDTO
->
{
LocalDate
hireDay
=
LocalDate
.
parse
(
feiShuEmployeeDTO
.
getSystemFields
().
getHireDate
());
// 使用plusMonths正好满足需求
return
hireDay
.
plusMonths
(
6L
).
equals
(
LocalDate
.
now
());
})
.
map
(
feiShuEmployeeDTO
->
{
// 给员工自己发消息
feiShuApiService
.
sendMsg
(
generateEmployeeMsgCard
(
feiShuEmployeeDTO
),
"open_id"
,
feiShuConfig
.
getAnniversaryApp
());
// 给领导发送消息
sendMsgToLeader
(
generateLeaderMsgCard
(
feiShuEmployeeDTO
),
feiShuEmployeeDTO
);
return
feiShuEmployeeDTO
;
}).
collect
(
Collectors
.
toList
());
log
.
info
(
"{} 当日转正人: {}"
,
LocalDate
.
now
(),
hireDayEmployees
);
}
@Override
public
FeiShuMsgDTO
generateEmployeeMsgCard
(
FeiShuEmployeeDTO
feiShuEmployeeDTO
){
String
name
=
feiShuEmployeeDTO
.
getSystemFields
().
getName
();
FeiShuMsgDTO
feiShuMsgDTO
=
new
FeiShuMsgDTO
();
feiShuMsgDTO
.
setMsgType
(
"interactive"
);
feiShuMsgDTO
.
setContent
(
String
.
format
(
getInteractiveCardStr
(
"/templates/conversion-employee.json"
),
name
,
name
));
feiShuMsgDTO
.
setReceiveId
(
feiShuEmployeeDTO
.
getUserId
());
return
feiShuMsgDTO
;
}
@Override
public
FeiShuMsgDTO
generateLeaderMsgCard
(
FeiShuEmployeeDTO
feiShuEmployeeDTO
)
{
FeiShuMsgDTO
feiShuMsgDTO
=
new
FeiShuMsgDTO
();
feiShuMsgDTO
.
setMsgType
(
"interactive"
);
feiShuMsgDTO
.
setContent
(
String
.
format
(
getInteractiveCardStr
(
"/templates/conversion-leader.json"
),
feiShuEmployeeDTO
.
getSystemFields
().
getName
()));
return
feiShuMsgDTO
;
}
}
src/main/java/com/pipihelper/project/feishu/service/doc/DocHelperService.java
deleted
100644 → 0
View file @
6bb6d59
package
com
.
pipihelper
.
project
.
feishu
.
service
.
doc
;
import
com.github.benmanes.caffeine.cache.Cache
;
import
com.github.benmanes.caffeine.cache.Caffeine
;
import
com.pipihelper.project.feishu.dto.AppConfig
;
import
com.pipihelper.project.feishu.dto.FeiShuConfig
;
import
com.pipihelper.project.feishu.dto.FeiShuCreateTaskDTO
;
import
com.pipihelper.project.feishu.dto.doc.DocDTO
;
import
com.pipihelper.project.feishu.dto.doc.FieldsDTO
;
import
com.pipihelper.project.feishu.dto.doc.PeopleDTO
;
import
com.pipihelper.project.feishu.dto.employee.FeiShuEmployeeDTO
;
import
com.pipihelper.project.feishu.dto.msg.ContentDTO
;
import
com.pipihelper.project.feishu.dto.msg.FeiShuBatchMsgDTO
;
import
com.pipihelper.project.feishu.service.FeiShuApiService
;
import
com.pipihelper.project.feishu.vo.CreateTaskVo
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
org.springframework.util.CollectionUtils
;
import
javax.annotation.Resource
;
import
java.time.*
;
import
java.time.format.DateTimeFormatter
;
import
java.util.*
;
/**
* @author xiongjian
* @date 2022/7/4
*/
@Service
@Slf4j
public
class
DocHelperService
{
@Autowired
private
FeiShuApiService
feiShuApiService
;
@Resource
private
FeiShuConfig
feiShuConfig
;
private
final
Cache
<
String
,
Map
<
String
,
String
>>
NAME_CACHE
=
Caffeine
.
newBuilder
()
.
maximumSize
(
5
)
.
expireAfterWrite
(
Duration
.
ofHours
(
2
))
.
build
();
private
final
DateTimeFormatter
DATE_TIME_FORMATTER
=
DateTimeFormatter
.
ofPattern
(
"yyyy-MM-dd HH:mm"
);
private
Map
<
String
,
String
>
getNameMap
()
{
return
NAME_CACHE
.
get
(
"nameMap"
,
map
->
{
List
<
FeiShuEmployeeDTO
>
feiShuEmployeeDTOList
=
feiShuApiService
.
getEmployeeList
(
feiShuConfig
.
getAnniversaryApp
());
HashMap
<
String
,
String
>
nameMap
=
new
HashMap
<>(
feiShuEmployeeDTOList
.
size
());
for
(
FeiShuEmployeeDTO
feiShuEmployeeDTO
:
feiShuEmployeeDTOList
)
{
String
key
=
feiShuEmployeeDTO
.
getSystemFields
().
getName
();
nameMap
.
put
(
key
,
feiShuEmployeeDTO
.
getUserId
());
}
log
.
info
(
"重建姓名-Id缓存, size: {}"
,
nameMap
.
size
());
return
nameMap
;
});
}
/**
* 人员转换器
*/
public
void
transferPeople
()
{
String
app
=
feiShuConfig
.
getAnniversaryApp
();
AppConfig
appConfig
=
feiShuConfig
.
getAppConfigMap
().
get
(
app
);
List
<
DocDTO
>
docList
=
feiShuApiService
.
getTableRecords
(
appConfig
.
getTableId
(),
appConfig
.
getPeopleTableId
(),
app
);
for
(
DocDTO
<
FieldsDTO
>
docDTO
:
docList
)
{
if
(
Objects
.
isNull
(
docDTO
.
getFields
().
getName
()))
{
continue
;
}
if
(
getNameMap
().
containsKey
(
docDTO
.
getFields
().
getName
())
&&
CollectionUtils
.
isEmpty
(
docDTO
.
getFields
().
getPeople
()))
{
List
<
PeopleDTO
>
list
=
new
ArrayList
<>();
list
.
add
(
new
PeopleDTO
(
getNameMap
().
get
(
docDTO
.
getFields
().
getName
())));
docDTO
.
getFields
().
setPeople
(
list
);
docDTO
.
getFields
().
setUserId
(
getNameMap
().
get
(
docDTO
.
getFields
().
getName
()));
docDTO
.
getFields
().
setUpdateTime
(
LocalDateTime
.
now
().
atZone
(
ZoneId
.
systemDefault
()).
toInstant
().
toEpochMilli
());
docDTO
.
getFields
().
setToken
(
"Bearer "
+
feiShuApiService
.
getTenantToken
(
app
));
feiShuApiService
.
updateTableRecords
(
appConfig
.
getTableId
(),
appConfig
.
getPeopleTableId
(),
docDTO
.
getRecordId
(),
app
,
docDTO
);
}
}
}
/**
* 通过表格创建任务
*/
public
void
createTaskByTable
()
{
String
app
=
feiShuConfig
.
getAnniversaryApp
();
AppConfig
appConfig
=
feiShuConfig
.
getAppConfigMap
().
get
(
app
);
List
<
DocDTO
>
docList
=
feiShuApiService
.
getTableRecords
(
appConfig
.
getTableId
(),
appConfig
.
getTaskTableId
(),
app
);
for
(
DocDTO
<
FieldsDTO
>
docDTO
:
docList
)
{
if
(
docDTO
.
getFields
()
==
null
)
{
continue
;
}
if
(
StringUtils
.
isBlank
(
docDTO
.
getFields
().
getTaskName
()))
{
continue
;
}
if
(!
"待创建"
.
equals
(
docDTO
.
getFields
().
getStatues
()))
{
continue
;
}
if
(
StringUtils
.
isBlank
(
docDTO
.
getFields
().
getCollaborators
()))
{
continue
;
}
// 创建任务
FeiShuCreateTaskDTO
feiShuCreateTaskDTO
=
new
FeiShuCreateTaskDTO
();
feiShuCreateTaskDTO
.
setSummary
(
docDTO
.
getFields
().
getTaskName
());
feiShuCreateTaskDTO
.
setDescription
(
docDTO
.
getFields
().
getTaskDescription
());
FeiShuCreateTaskDTO
.
Due
due
=
new
FeiShuCreateTaskDTO
.
Due
();
if
(
docDTO
.
getFields
().
getDue
()
!=
null
)
{
due
.
setTime
(
String
.
valueOf
(
docDTO
.
getFields
().
getDue
()).
substring
(
0
,
10
));
}
feiShuCreateTaskDTO
.
setDue
(
due
);
FeiShuCreateTaskDTO
.
OriginDTO
originDTO
=
new
FeiShuCreateTaskDTO
.
OriginDTO
();
originDTO
.
setPlatformI18nName
(
String
.
format
(
"{\"zh_cn\": \"%s\"}"
,
docDTO
.
getFields
().
getOrigin
()));
feiShuCreateTaskDTO
.
setOrigin
(
originDTO
);
// 执行者
String
[]
collaborators
=
docDTO
.
getFields
().
getCollaborators
().
split
(
",|,"
);
List
<
String
>
collaboratorIds
=
new
ArrayList
<>();
for
(
String
collaborator
:
collaborators
)
{
if
(
getNameMap
().
containsKey
(
collaborator
))
{
collaboratorIds
.
add
(
getNameMap
().
get
(
collaborator
));
}
}
feiShuCreateTaskDTO
.
setCollaboratorIds
(
collaboratorIds
);
// 关注者
if
(
docDTO
.
getFields
().
getFollowers
()
!=
null
)
{
String
[]
followers
=
docDTO
.
getFields
().
getFollowers
().
split
(
",|,"
);
List
<
String
>
followerIds
=
new
ArrayList
<>();
for
(
String
follower
:
followers
)
{
if
(
getNameMap
().
containsKey
(
follower
))
{
followerIds
.
add
(
getNameMap
().
get
(
follower
));
}
}
feiShuCreateTaskDTO
.
setFollowerIds
(
followerIds
);
}
try
{
// 创建任务
feiShuApiService
.
createTask
(
feiShuCreateTaskDTO
,
null
,
app
);
// 发送消息
sendMsg
(
docDTO
);
docDTO
.
getFields
().
setNote
(
"成功"
);
}
catch
(
Exception
e
)
{
docDTO
.
getFields
().
setNote
(
e
.
getMessage
());
}
finally
{
docDTO
.
getFields
().
setStatues
(
"已创建"
);
docDTO
.
getFields
().
setUpdateTime
(
LocalDateTime
.
now
().
atZone
(
ZoneId
.
systemDefault
()).
toInstant
().
toEpochMilli
());
// 更新数据表
feiShuApiService
.
updateTableRecords
(
appConfig
.
getTableId
(),
appConfig
.
getTaskTableId
(),
docDTO
.
getRecordId
(),
app
,
docDTO
);
}
}
}
public
void
createTask
(
CreateTaskVo
createTaskVo
)
{
String
app
=
feiShuConfig
.
getAnniversaryApp
();
// 创建任务
FeiShuCreateTaskDTO
feiShuCreateTaskDTO
=
new
FeiShuCreateTaskDTO
();
feiShuCreateTaskDTO
.
setSummary
(
createTaskVo
.
getSummary
());
feiShuCreateTaskDTO
.
setDescription
(
createTaskVo
.
getDescription
());
FeiShuCreateTaskDTO
.
Due
due
=
new
FeiShuCreateTaskDTO
.
Due
();
ZoneId
zone
=
ZoneId
.
systemDefault
();
if
(
StringUtils
.
isNotBlank
(
createTaskVo
.
getDueTime
()))
{
// 截止时间有值按填值截止
Long
time
=
LocalDateTime
.
parse
(
createTaskVo
.
getDueTime
(),
DATE_TIME_FORMATTER
).
atZone
(
zone
).
toInstant
().
getEpochSecond
();
due
.
setTime
(
String
.
valueOf
(
time
));
}
else
{
// 截止时间无值,按当天18点+偏移量截止
LocalDateTime
dateTime
=
LocalDateTime
.
of
(
LocalDate
.
now
(),
LocalTime
.
of
(
18
,
0
)).
plusHours
(
createTaskVo
.
getDueTimeOffset
());
Long
time
=
dateTime
.
atZone
(
zone
).
toInstant
().
getEpochSecond
();
due
.
setTime
(
String
.
valueOf
(
time
));
}
feiShuCreateTaskDTO
.
setDue
(
due
);
FeiShuCreateTaskDTO
.
OriginDTO
originDTO
=
new
FeiShuCreateTaskDTO
.
OriginDTO
();
originDTO
.
setPlatformI18nName
(
String
.
format
(
"{\"zh_cn\": \"%s\"}"
,
app
));
feiShuCreateTaskDTO
.
setOrigin
(
originDTO
);
// 执行者
if
(
StringUtils
.
isNotBlank
(
createTaskVo
.
getCollaboratorIds
())){
List
<
String
>
collaboratorIds
=
new
ArrayList
<>();
for
(
String
name
:
getNameMap
().
keySet
())
{
if
(
createTaskVo
.
getCollaboratorIds
().
contains
(
name
)){
collaboratorIds
.
add
(
getNameMap
().
get
(
name
));
}
}
feiShuCreateTaskDTO
.
setCollaboratorIds
(
collaboratorIds
);
}
// 关注者
if
(
StringUtils
.
isNotBlank
(
createTaskVo
.
getFollowerIds
())){
List
<
String
>
followersIds
=
new
ArrayList
<>();
for
(
String
name
:
getNameMap
().
keySet
())
{
if
(
createTaskVo
.
getFollowerIds
().
contains
(
name
)){
followersIds
.
add
(
getNameMap
().
get
(
name
));
}
}
feiShuCreateTaskDTO
.
setFollowerIds
(
followersIds
);
}
// 创建任务
feiShuApiService
.
createTask
(
feiShuCreateTaskDTO
,
null
,
app
);
}
public
void
sendMsg
(
DocDTO
<
FieldsDTO
>
docDTO
)
{
if
(
StringUtils
.
isBlank
(
docDTO
.
getFields
().
getMsg
()))
{
return
;
}
if
(
StringUtils
.
isBlank
(
docDTO
.
getFields
().
getReceiverIds
()))
{
return
;
}
FeiShuBatchMsgDTO
feiShuBatchMsgDTO
=
new
FeiShuBatchMsgDTO
();
feiShuBatchMsgDTO
.
setMsgType
(
"text"
);
feiShuBatchMsgDTO
.
setContent
(
new
ContentDTO
(
docDTO
.
getFields
().
getMsg
()));
String
[]
receivers
=
docDTO
.
getFields
().
getReceiverIds
().
split
(
",|,"
);
List
<
String
>
receiverIds
=
new
ArrayList
<>();
for
(
String
receiver
:
receivers
)
{
if
(
getNameMap
().
containsKey
(
receiver
))
{
receiverIds
.
add
(
getNameMap
().
get
(
receiver
));
}
}
feiShuBatchMsgDTO
.
setOpenIds
(
receiverIds
);
// 发送消息
feiShuApiService
.
sendBatchMsg
(
feiShuBatchMsgDTO
,
feiShuConfig
.
getAnniversaryApp
());
}
}
src/main/resources/application-dev.yml
View file @
4a7e39e
...
...
@@ -11,11 +11,6 @@ spring:
# 飞书相关配置参数
feishu
:
feiShuOpenApiHost
:
https://open.feishu.cn/open-apis
testHelperApp
:
testHelperApp
anniversaryApp
:
anniversaryApp
# 测试小助手配置
appConfigMap[testHelperApp]
:
encryptKey
:
aGTqmJcfXluKWfFWHGw5SdzIg6QIxPsp
verificationToken
:
ChUEDdWQbyHpHUV6H5fVeL5fOP3HfBE6
appId
:
cli_a2cff17bd3f8d013
...
...
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment