Browse Source

Merge pull request #881 from colinin/Integrated-WeCom

WeCom integration
pull/914/head
yx lin 2 years ago
committed by GitHub
parent
commit
2f1d515040
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      apps/vue/src/api/auditing/model/auditLogModel.ts
  2. 2
      apps/vue/src/store/modules/settings.ts
  3. 2
      apps/vue/src/views/feature/src/FeatureModal.vue
  4. 3
      apps/vue/src/views/localization/resources/components/ResourceTable.vue
  5. 6
      apps/vue/src/views/localization/texts/components/ModalData.ts
  6. 4
      apps/vue/src/views/localization/texts/components/TextModal.vue
  7. 3
      aspnet-core/LINGYUN.MicroService.All.sln
  8. 4
      aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/EntityRestoreAppService.cs
  9. 5
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/GetFileMultiTenancyInput.cs
  10. 6
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeAppService.cs
  11. 1
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageAppService.cs
  12. 25
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work.HttpApi/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeController.cs
  13. 1
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN.Abp.WeChat.Work.csproj
  14. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkModule.cs
  15. 6
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeGenerator.cs
  16. 11
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkUserFinder.cs
  17. 43
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/IWeChatWorkAppChatManager.cs
  18. 32
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Models/WeChatWorkAppChatInfo.cs
  19. 56
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Request/WeChatWorkAppChatCreateRequest.cs
  20. 17
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Request/WeChatWorkAppChatRequest.cs
  21. 61
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Request/WeChatWorkAppChatUpdateRequest.cs
  22. 14
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Response/WeChatWorkAppChatCreateResponse.cs
  23. 14
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Response/WeChatWorkAppChatInfoResponse.cs
  24. 60
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/WeChatWorkAppChatManager.cs
  25. 46
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureDefinitionProvider.cs
  26. 24
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureNames.cs
  27. 15
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/en.json
  28. 19
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/zh-Hans.json
  29. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/IWeChatWorkMediaProvider.cs
  30. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/Models/WeChatWorkImageResponse.cs
  31. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/Models/WeChatWorkMediaRequest.cs
  32. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/Models/WeChatWorkMediaResponse.cs
  33. 13
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/WeChatWorkMediaProvider.cs
  34. 22
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageManager.cs
  35. 20
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageSender.cs
  36. 90
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/MiniProgramMessage.cs
  37. 34
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatFileMessage.cs
  38. 34
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatImageMessage.cs
  39. 34
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatMarkdownMessage.cs
  40. 34
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatMpNewMessage.cs
  41. 34
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatNewMessage.cs
  42. 34
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatTextCardMessage.cs
  43. 35
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatTextMessage.cs
  44. 34
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatVideoMessage.cs
  45. 25
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatVoiceMessage.cs
  46. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkFileMessage.cs
  47. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkImageMessage.cs
  48. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMarkdownMessage.cs
  49. 84
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMiniProgramMessage.cs
  50. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMpNewMessage.cs
  51. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkNewMessage.cs
  52. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkTextCardMessage.cs
  53. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkTextMessage.cs
  54. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkVideoMessage.cs
  55. 3
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkVoiceMessage.cs
  56. 27
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Request/WeChatWorkMessageReCallRequest.cs
  57. 11
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Request/WeChatWorkMessageRequest.cs
  58. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Response/WeChatWorkMessageResponse.cs
  59. 28
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCard.cs
  60. 31
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardAction.cs
  61. 31
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardActionMenu.cs
  62. 50
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardCardAction.cs
  63. 33
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardEmphasisContent.cs
  64. 93
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardHorizontalContent.cs
  65. 62
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardJump.cs
  66. 33
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardMainTitle.cs
  67. 68
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardQuoteArea.cs
  68. 52
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardSource.cs
  69. 81
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TextTemplateCard.cs
  70. 47
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/WeChatWorkTemplateCardMessage.cs
  71. 45
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkAppChatMessage.cs
  72. 11
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessage.cs
  73. 43
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageManager.cs
  74. 11
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageRequest.cs
  75. 38
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageSender.cs
  76. 4
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/IWeChatWorkCryptoService.cs
  77. 12
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoData.cs
  78. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoDecryptData.cs
  79. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoEchoData.cs
  80. 4
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoService.cs
  81. 35
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/IWeChatWorkTokenProvider.cs
  82. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkToken.cs
  83. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkTokenCacheItem.cs
  84. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkTokenRequest.cs
  85. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkTokenResponse.cs
  86. 201
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/WeChatWorkTokenProvider.cs
  87. 12
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkRequest.cs
  88. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkResponse.cs
  89. 46
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Auth.cs
  90. 68
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Chat.cs
  91. 70
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Media.cs
  92. 68
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Message.cs
  93. 123
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.cs
  94. 18
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpResponseDeserializeExtensions.cs
  95. 10
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/WeChatObjectSerializeExtensions.cs
  96. 11
      aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/WeChatWorkResponseDeserializeExtensions.cs
  97. 6
      aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/LY.MicroService.BackendAdmin.HttpApi.Host.csproj
  98. 20
      aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/appsettings.Development.json
  99. 3
      aspnet-core/tests/LINGYUN.Abp.WeChat.Work.Tests/GlobalUsings.cs
  100. 20
      aspnet-core/tests/LINGYUN.Abp.WeChat.Work.Tests/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkTestModule.cs

5
apps/vue/src/api/auditing/model/auditLogModel.ts

@ -91,3 +91,8 @@ export interface EntityChangeGetWithUsernameInput {
entityId?: string;
entityTypeFullName?: string;
}
export interface RestoreEntityInput {
entityId: string;
entityChangeId?: string;
}

2
apps/vue/src/store/modules/settings.ts

@ -27,7 +27,7 @@ export const useSettingManagementStore = defineStore({
initlize(settingKey: string, api: (...args) => Promise<ListResultDto<SettingGroup>>) {
this.settingKey = settingKey;
if (this.settings.length === 0) {
ls.get(this.settingKey) || this.refreshSettings(api);
this.settings = ls.get(this.settingKey) || this.refreshSettings(api);
}
},
refreshSettings(api: (...args) => Promise<ListResultDto<SettingGroup>>) {

2
apps/vue/src/views/feature/src/FeatureModal.vue

@ -9,7 +9,7 @@
@ok="handleSubmit"
@cancel="onGroupChange(0)"
>
<Form ref="formRel" :model="featureGroup" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
<Form ref="formRel" :model="featureGroup">
<Tabs tabPosition="left" v-model:activeKey="featureGroupKey" @change="onGroupChange">
<TabPane v-for="(group, gi) in featureGroup.groups" :key="gi" :tab="group.displayName">
<div v-for="(feature, fi) in group.features" :key="feature.name">

3
apps/vue/src/views/localization/resources/components/ResourceTable.vue

@ -7,7 +7,7 @@
type="primary"
@click="handleAddNew"
>
{{ L('Language:AddNew') }}
{{ L('Resource:AddNew') }}
</Button>
</template>
<template #bodyCell="{ column, record }">
@ -47,7 +47,6 @@
import { getList, GetAsyncByName, DeleteAsyncByName } from '/@/api/localization/resources';
import { Resource } from '/@/api/localization/model/resourcesModel';
import { getDataColumns } from './TableData';
import { reactive } from 'vue';
import ResourceModal from './ResourceModal.vue';

6
apps/vue/src/views/localization/texts/components/ModalData.ts

@ -17,7 +17,7 @@ export function getSearchFormSchemas(submitFunc?: () => Promise<void>): Partial<
colProps: { span: 6 },
required: true,
componentProps: {
api: () => getLanguages(),
api: getLanguages,
resultField: 'items',
labelField: 'displayName',
valueField: 'cultureName',
@ -30,7 +30,7 @@ export function getSearchFormSchemas(submitFunc?: () => Promise<void>): Partial<
colProps: { span: 6 },
required: true,
componentProps: {
api: () => getLanguages(),
api: getLanguages,
resultField: 'items',
labelField: 'displayName',
valueField: 'cultureName',
@ -42,7 +42,7 @@ export function getSearchFormSchemas(submitFunc?: () => Promise<void>): Partial<
label: L('DisplayName:ResourceName'),
colProps: { span: 6 },
componentProps: {
api: () => getResources(),
api: getResources,
resultField: 'items',
labelField: 'displayName',
valueField: 'name',

4
apps/vue/src/views/localization/texts/components/TextModal.vue

@ -43,7 +43,7 @@
colProps: { span: 24 },
required: true,
componentProps: {
api: () => getLanguages(),
api: getLanguages,
resultField: 'items',
labelField: 'uiCultureName',
valueField: 'cultureName',
@ -80,7 +80,7 @@
colProps: { span: 24 },
required: true,
componentProps: {
api: () => getResources(),
api: getResources,
resultField: 'items',
labelField: 'displayName',
valueField: 'name',

3
aspnet-core/LINGYUN.MicroService.All.sln

@ -353,6 +353,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
common.props = common.props
configureawait.props = configureawait.props
Directory.Build.props = Directory.Build.props
NuGet.Config = NuGet.Config
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Tencent.SettingManagement", "modules\cloud-tencent\LINGYUN.Abp.Tencent.SettingManagement\LINGYUN.Abp.Tencent.SettingManagement.csproj", "{C7CF4193-6397-4450-AF42-3BACD7CF292E}"
@ -1793,7 +1794,7 @@ Global
{5D0ED1FC-3A7C-4531-9512-832E73AD9555} = {0439B173-F41E-4CE0-A44A-CCB70328F272}
{2BF7FB73-0C62-4ECF-99F0-0583855D2777} = {52B5D4F7-237B-4E0A-A167-68442164F70A}
{6FE7E243-2D99-4567-8786-6C9283D608EF} = {52B5D4F7-237B-4E0A-A167-68442164F70A}
{685188AC-A145-4A27-BF5F-9C970A59AA9C} = {672E1170-7B18-474B-85C7-1961BF2A48AE}
{685188AC-A145-4A27-BF5F-9C970A59AA9C} = {E2408063-FB1F-4513-B4A7-1FE50667C6E8}
{6AA0785D-9B6C-4EAE-AB83-0C4CF2B6B473} = {8AC72641-30D3-4ACF-89FA-808FADC55C2E}
{65DE28D5-DFEA-43E5-B820-BAF09A1FC4ED} = {8AC72641-30D3-4ACF-89FA-808FADC55C2E}
{D3E65610-4167-4235-9C9D-1E1FAD4C0CE6} = {8AC72641-30D3-4ACF-89FA-808FADC55C2E}

4
aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/EntityRestoreAppService.cs

@ -92,10 +92,6 @@ public abstract class EntityRestoreAppService<TEntity, TKey> : EntityChangeAppSe
}
var currentValue = propertyChange.OriginalValue;
if (input.EntityChangeId.HasValue)
{
currentValue = propertyChange.NewValue;
}
if (currentValue.IsNullOrWhiteSpace() || string.Equals("null", currentValue, StringComparison.InvariantCultureIgnoreCase))
{
if (isNullableType)

5
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/GetFileMultiTenancyInput.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.OssManagement;
@ -13,6 +14,10 @@ public abstract class GetFileMultiTenancyInput
{
if (!TenantId.IsNullOrWhiteSpace())
{
if ("g".Equals(TenantId, StringComparison.InvariantCultureIgnoreCase))
{
return null;
}
if ("global".Equals(TenantId, StringComparison.InvariantCultureIgnoreCase))
{
return null;

6
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeAppService.cs

@ -1,8 +1,6 @@
using LINGYUN.Abp.WeChat.Work.Settings;
using System;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Security.Encryption;
@ -27,7 +25,7 @@ public class WeChatWorkAuthorizeAppService : ApplicationService, IWeChatWorkAuth
{
var state = _encryptionService.Encrypt($"agentid={agentid}&redirectUri={redirectUri}&responseType={responseType}&scope={scope}&random={Guid.NewGuid():D}").ToMd5();
return await _authorizeGenerator.GenerateOAuth2AuthorizeAsync(agentid, HttpUtility.UrlEncode(redirectUri, Encoding.UTF8), state, responseType, scope);
return await _authorizeGenerator.GenerateOAuth2AuthorizeAsync(agentid, redirectUri, state, responseType, scope);
}
public async virtual Task<string> GenerateOAuth2LoginAsync(string redirectUri, string loginType = "ServiceApp", string agentid = "")
@ -38,6 +36,6 @@ public class WeChatWorkAuthorizeAppService : ApplicationService, IWeChatWorkAuth
Check.NotNullOrEmpty(corpId, nameof(corpId));
return await _authorizeGenerator.GenerateOAuth2LoginAsync(corpId, HttpUtility.UrlEncode(redirectUri, Encoding.UTF8), state, loginType, agentid);
return await _authorizeGenerator.GenerateOAuth2LoginAsync(corpId, redirectUri, state, loginType, agentid);
}
}

1
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageAppService.cs

@ -1,4 +1,5 @@
using LINGYUN.Abp.WeChat.Work.Security;
using LINGYUN.Abp.WeChat.Work.Security.Models;
using LINGYUN.Abp.WeChat.Work.Settings;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;

25
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work.HttpApi/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeController.cs

@ -31,6 +31,19 @@ public class WeChatWorkAuthorizeController : AbpControllerBase, IWeChatWorkAutho
return _service.GenerateOAuth2AuthorizeAsync(agentid, redirectUri, responseType, scope);
}
[HttpGet]
[Route("oauth2/authorize")]
public async virtual Task<IActionResult> OAuth2AuthorizeAsync(
[FromQuery(Name = "agent_id")] string agentid,
[FromQuery(Name = "redirect_uri")] string redirectUri,
[FromQuery(Name = "response_type")] string responseType = "code",
[FromQuery] string scope = "snsapi_base")
{
var url = await _service.GenerateOAuth2AuthorizeAsync(agentid, redirectUri, responseType, scope);
return Redirect(url);
}
[HttpGet]
[Route("oauth2/login")]
public virtual Task<string> GenerateOAuth2LoginAsync(
@ -40,4 +53,16 @@ public class WeChatWorkAuthorizeController : AbpControllerBase, IWeChatWorkAutho
{
return _service.GenerateOAuth2LoginAsync(redirectUri, loginType, agentid);
}
[HttpGet]
[Route("oauth2/login/sso")]
public async virtual Task<IActionResult> OAuth2LoginAsync(
[FromQuery(Name = "redirect_uri")] string redirectUri,
[FromQuery(Name = "login_type")] string loginType = "ServiceApp",
[FromQuery(Name = "agent_id")] string agentid = "")
{
var url = await _service.GenerateOAuth2LoginAsync(redirectUri, loginType, agentid);
return Redirect(url);
}
}

1
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN.Abp.WeChat.Work.csproj

@ -14,6 +14,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.ExceptionHandling" Version="$(VoloAbpPackageVersion)" />
<PackageReference Include="Volo.Abp.Features" Version="$(VoloAbpPackageVersion)" />
<PackageReference Include="Volo.Abp.Caching" Version="$(VoloAbpPackageVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkModule.cs

@ -3,6 +3,7 @@ using LINGYUN.Abp.WeChat.Work.Localization;
using Microsoft.Extensions.DependencyInjection;
using System;
using Volo.Abp.Caching;
using Volo.Abp.ExceptionHandling;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
@ -13,6 +14,7 @@ namespace LINGYUN.Abp.WeChat.Work;
[DependsOn(
typeof(AbpCachingModule),
typeof(AbpExceptionHandlingModule),
typeof(AbpFeaturesLimitValidationModule),
typeof(AbpSettingsModule))]
public class AbpWeChatWorkModule : AbpModule

6
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkAuthorizeGenerator.cs

@ -1,4 +1,5 @@
using LINGYUN.Abp.WeChat.Work.Settings;
using LINGYUN.Abp.WeChat.Work.Features;
using LINGYUN.Abp.WeChat.Work.Settings;
using System;
using System.Net.Http;
using System.Text;
@ -6,9 +7,12 @@ using System.Threading.Tasks;
using System.Web;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
using Volo.Abp.Settings;
namespace LINGYUN.Abp.WeChat.Work.Authorize;
[RequiresFeature(WeChatWorkFeatureNames.Enable)]
public class WeChatWorkAuthorizeGenerator : IWeChatWorkAuthorizeGenerator, ISingletonDependency
{
protected ISettingProvider SettingProvider { get; }

11
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Authorize/WeChatWorkUserFinder.cs

@ -1,14 +1,17 @@
using LINGYUN.Abp.WeChat.Work.Authorize.Models;
using LINGYUN.Abp.WeChat.Work.Authorize.Request;
using LINGYUN.Abp.WeChat.Work.Authorize.Response;
using LINGYUN.Abp.WeChat.Work.Features;
using LINGYUN.Abp.WeChat.Work.Token;
using Newtonsoft.Json;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
namespace LINGYUN.Abp.WeChat.Work.Authorize;
[RequiresFeature(WeChatWorkFeatureNames.Enable)]
public class WeChatWorkUserFinder : IWeChatWorkUserFinder, ISingletonDependency
{
protected IHttpClientFactory HttpClientFactory { get; }
@ -31,8 +34,7 @@ public class WeChatWorkUserFinder : IWeChatWorkUserFinder, ISingletonDependency
var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient);
using var response = await client.GetUserInfoAsync(token.AccessToken, code, cancellationToken);
var responseContent = await response.Content.ReadAsStringAsync();
var userInfoResponse = JsonConvert.DeserializeObject<WeChatWorkUserInfoResponse>(responseContent);
var userInfoResponse = await response.DeserializeObjectAsync<WeChatWorkUserInfoResponse>();
return userInfoResponse.ToUserInfo();
}
@ -47,8 +49,7 @@ public class WeChatWorkUserFinder : IWeChatWorkUserFinder, ISingletonDependency
var request = new WeChatWorkUserDetailRequest(userTicket);
using var response = await client.GetUserDetailAsync(token.AccessToken, request, cancellationToken);
var responseContent = await response.Content.ReadAsStringAsync();
var userDetailResponse = JsonConvert.DeserializeObject<WeChatWorkUserDetailResponse>(responseContent);
var userDetailResponse = await response.DeserializeObjectAsync<WeChatWorkUserDetailResponse>();
return userDetailResponse.ToUserDetail();
}

43
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/IWeChatWorkAppChatManager.cs

@ -0,0 +1,43 @@
using LINGYUN.Abp.WeChat.Work.Chat.Request;
using LINGYUN.Abp.WeChat.Work.Chat.Response;
using System.Threading;
using System.Threading.Tasks;
namespace LINGYUN.Abp.WeChat.Work.Chat;
/// <summary>
/// 群聊操作接口
/// </summary>
/// <remarks>
/// 参考:https://developer.work.weixin.qq.com/document/path/90244
/// </remarks>
public interface IWeChatWorkAppChatManager
{
/// <summary>
/// 创建群聊会话
/// </summary>
/// <remarks>
/// 参考:https://developer.work.weixin.qq.com/document/path/90245
/// </remarks>
Task<WeChatWorkAppChatCreateResponse> CreateAsync(
WeChatWorkAppChatCreateRequest request,
CancellationToken cancellationToken = default);
/// <summary>
/// 修改群聊会话
/// </summary>
/// <remarks>
/// 参考:https://developer.work.weixin.qq.com/document/path/98913
/// </remarks>
Task<WeChatWorkResponse> UpdateAsync(
WeChatWorkAppChatUpdateRequest request,
CancellationToken cancellationToken = default);
/// <summary>
/// 获取群聊会话
/// </summary>
/// <remarks>
/// 参考:https://developer.work.weixin.qq.com/document/path/98914
/// </remarks>
Task<WeChatWorkAppChatInfoResponse> GetAsync(
string agentId,
string chatId,
CancellationToken cancellationToken = default);
}

32
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Models/WeChatWorkAppChatInfo.cs

@ -0,0 +1,32 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Chat.Models;
public class WeChatWorkAppChatInfo
{
/// <summary>
/// 群聊名
/// </summary>
[JsonProperty("name")]
[JsonPropertyName("name")]
public virtual string Name { get; set; }
/// <summary>
/// 群主id
/// </summary>
[JsonProperty("owner")]
[JsonPropertyName("owner")]
public virtual string Owner { get; set; }
/// <summary>
/// 群成员id列表
/// </summary>
[JsonProperty("userlist")]
[JsonPropertyName("userlist")]
public virtual List<string> Users { get; set; }
/// <summary>
/// 群聊唯一标志
/// </summary>
[JsonProperty("chatid")]
[JsonPropertyName("chatid")]
public virtual string ChatId { get; set; }
}

56
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Request/WeChatWorkAppChatCreateRequest.cs

@ -0,0 +1,56 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Chat.Request;
public class WeChatWorkAppChatCreateRequest : WeChatWorkAppChatRequest
{
public WeChatWorkAppChatCreateRequest(
string agentId,
string name,
List<string> users,
string owner = null,
string chatId = null)
: base(agentId)
{
Name = name;
Owner = owner;
Users = users;
ChatId = chatId;
}
/// <summary>
/// 群聊名,最多50个utf8字符,超过将截断
/// </summary>
[NotNull]
[JsonProperty("name")]
[JsonPropertyName("name")]
public virtual string Name { get; set; }
/// <summary>
/// 指定群主的id。
/// 如果不指定,系统会随机从userlist中选一人作为群主
/// </summary>
[CanBeNull]
[JsonProperty("owner")]
[JsonPropertyName("owner")]
public virtual string Owner { get; set; }
/// <summary>
/// 群成员id列表。
/// 至少2人,至多2000人
/// </summary>
[NotNull]
[JsonProperty("userlist")]
[JsonPropertyName("userlist")]
public virtual List<string> Users { get; set; }
/// <summary>
/// 群聊的唯一标志,不能与已有的群重复;
/// 字符串类型,最长32个字符。
/// 只允许字符0-9及字母a-zA-Z。
/// 如果不填,系统会随机生成群id
/// </summary>
[CanBeNull]
[JsonProperty("chatid")]
[JsonPropertyName("chatid")]
public virtual string ChatId { get; set; }
}

17
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Request/WeChatWorkAppChatRequest.cs

@ -0,0 +1,17 @@
using JetBrains.Annotations;
namespace LINGYUN.Abp.WeChat.Work.Chat.Request;
public abstract class WeChatWorkAppChatRequest : WeChatWorkRequest
{
/// <summary>
/// 应用标识
/// </summary>
[NotNull]
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public virtual string AgentId { get; set; }
protected WeChatWorkAppChatRequest(string agentId)
{
AgentId = agentId;
}
}

61
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Request/WeChatWorkAppChatUpdateRequest.cs

@ -0,0 +1,61 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Chat.Request;
public class WeChatWorkAppChatUpdateRequest : WeChatWorkAppChatRequest
{
public WeChatWorkAppChatUpdateRequest(
string agentId,
string chatId,
string name = null,
string owner = null,
List<string> addUsers = null,
List<string> delUsers = null)
: base(agentId)
{
Name = name;
Owner = owner;
AddUsers = addUsers;
DelUsers = delUsers;
ChatId = chatId;
}
/// <summary>
/// 新的群聊名。若不需更新,请忽略此参数。最多50个utf8字符,超过将截断
/// </summary>
[CanBeNull]
[JsonProperty("name")]
[JsonPropertyName("name")]
public virtual string Name { get; set; }
/// <summary>
/// 新群主的id。
/// 若不需更新,请忽略此参数。课程群聊群主必须在设置的群主列表内
/// </summary>
[CanBeNull]
[JsonProperty("owner")]
[JsonPropertyName("owner")]
public virtual string Owner { get; set; }
/// <summary>
/// 添加成员的id列表
/// </summary>
[CanBeNull]
[JsonProperty("add_user_list")]
[JsonPropertyName("add_user_list")]
public virtual List<string> AddUsers { get; set; }
/// <summary>
/// 踢出成员的id列表
/// </summary>
[CanBeNull]
[JsonProperty("del_user_list")]
[JsonPropertyName("del_user_list")]
public virtual List<string> DelUsers { get; set; }
/// <summary>
/// 群聊id
/// </summary>
[NotNull]
[JsonProperty("chatid")]
[JsonPropertyName("chatid")]
public virtual string ChatId { get; set; }
}

14
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Response/WeChatWorkAppChatCreateResponse.cs

@ -0,0 +1,14 @@
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Chat.Response;
public class WeChatWorkAppChatCreateResponse : WeChatWorkResponse
{
/// <summary>
/// 群聊的唯一标志
/// </summary>
[JsonProperty("chatid")]
[JsonPropertyName("chatid")]
public virtual string ChatId { get; set; }
}

14
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/Response/WeChatWorkAppChatInfoResponse.cs

@ -0,0 +1,14 @@
using LINGYUN.Abp.WeChat.Work.Chat.Models;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Chat.Response;
public class WeChatWorkAppChatInfoResponse : WeChatWorkResponse
{
/// <summary>
/// 群聊信息
/// </summary>
[JsonProperty("chat_info")]
[JsonPropertyName("chat_info")]
public WeChatWorkAppChatInfo ChatInfo { get; set; }
}

60
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Chat/WeChatWorkAppChatManager.cs

@ -0,0 +1,60 @@
using LINGYUN.Abp.WeChat.Work.Chat.Request;
using LINGYUN.Abp.WeChat.Work.Chat.Response;
using LINGYUN.Abp.WeChat.Work.Features;
using LINGYUN.Abp.WeChat.Work.Token;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
namespace LINGYUN.Abp.WeChat.Work.Chat;
[RequiresFeature(WeChatWorkFeatureNames.Enable)]
public class WeChatWorkAppChatManager : IWeChatWorkAppChatManager, ISingletonDependency
{
protected IHttpClientFactory HttpClientFactory { get; }
protected IWeChatWorkTokenProvider WeChatWorkTokenProvider { get; }
public WeChatWorkAppChatManager(
IHttpClientFactory httpClientFactory,
IWeChatWorkTokenProvider weChatWorkTokenProvider)
{
HttpClientFactory = httpClientFactory;
WeChatWorkTokenProvider = weChatWorkTokenProvider;
}
public async virtual Task<WeChatWorkAppChatCreateResponse> CreateAsync(
WeChatWorkAppChatCreateRequest request,
CancellationToken cancellationToken = default)
{
var token = await WeChatWorkTokenProvider.GetTokenAsync(request.AgentId, cancellationToken);
var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient);
using var response = await client.CreateAppChatAsync(token.AccessToken, request, cancellationToken);
return await response.DeserializeObjectAsync<WeChatWorkAppChatCreateResponse>();
}
public async virtual Task<WeChatWorkAppChatInfoResponse> GetAsync(
string agentId,
string chatId,
CancellationToken cancellationToken = default)
{
var token = await WeChatWorkTokenProvider.GetTokenAsync(agentId, cancellationToken);
var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient);
using var response = await client.GetAppChatAsync(token.AccessToken, agentId, cancellationToken);
return await response.DeserializeObjectAsync<WeChatWorkAppChatInfoResponse>();
}
public async virtual Task<WeChatWorkResponse> UpdateAsync(
WeChatWorkAppChatUpdateRequest request,
CancellationToken cancellationToken = default)
{
var token = await WeChatWorkTokenProvider.GetTokenAsync(request.AgentId, cancellationToken);
var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient);
using var response = await client.UpdateAppChatAsync(token.AccessToken, request, cancellationToken);
return await response.DeserializeObjectAsync<WeChatWorkAppChatCreateResponse>();
}
}

46
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureDefinitionProvider.cs

@ -12,31 +12,59 @@ public class WeChatWorkFeatureDefinitionProvider : FeatureDefinitionProvider
name: WeChatWorkFeatureNames.GroupName,
displayName: L("Features:WeChatWork"));
var weChatWorkEnableFeature = group.AddFeature(
var wechatWorkFeature = group.AddFeature(
name: WeChatWorkFeatureNames.Enable,
defaultValue: "false",
displayName: L("Features:WeChatWorkEnable"),
description: L("Features:WeChatWorkEnableDesc"),
valueType: new ToggleStringValueType(new BooleanValueValidator()));
var messageEnableFeature = weChatWorkEnableFeature.CreateChild(
AddMessageFeature(wechatWorkFeature);
AddAppChatFeature(wechatWorkFeature);
}
protected virtual void AddMessageFeature(FeatureDefinition wechatWorkFeature)
{
var messageEnableFeature = wechatWorkFeature.CreateChild(
name: WeChatWorkFeatureNames.Message.Enable,
defaultValue: "false",
displayName: L("Features:MessageEnable"),
description: L("Features:MessageEnableDesc"),
valueType: new ToggleStringValueType(new BooleanValueValidator()));
messageEnableFeature.CreateChild(
name: WeChatWorkFeatureNames.Message.SendLimit,
name: WeChatWorkFeatureNames.Message.Limit,
defaultValue: "20000",
displayName: L("Features:Message.SendLimit"),
description: L("Features:Message.SendLimitDesc"),
displayName: L("Features:Message.Limit"),
description: L("Features:Message.LimitDesc"),
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 100000)));
messageEnableFeature.CreateChild(
name: WeChatWorkFeatureNames.Message.SendLimitInterval,
name: WeChatWorkFeatureNames.Message.LimitInterval,
defaultValue: "1",
displayName: L("Features:Message.LimitInterval"),
description: L("Features:Message.LimitIntervalDesc"),
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 1000)));
}
protected virtual void AddAppChatFeature(FeatureDefinition wechatWorkFeature)
{
var messageEnableFeature = wechatWorkFeature.CreateChild(
name: WeChatWorkFeatureNames.AppChat.Message.Enable,
defaultValue: "false",
displayName: L("Features:AppChatMessageEnable"),
description: L("Features:AppChatMessageEnableDesc"),
valueType: new ToggleStringValueType(new BooleanValueValidator()));
messageEnableFeature.CreateChild(
name: WeChatWorkFeatureNames.AppChat.Message.Limit,
defaultValue: "20000",
displayName: L("Features:AppChatMessage.Limit"),
description: L("Features:AppChatMessage.LimitDesc"),
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 20000)));
messageEnableFeature.CreateChild(
name: WeChatWorkFeatureNames.AppChat.Message.LimitInterval,
defaultValue: "1",
displayName: L("Features:Message.SendLimitInterval"),
description: L("Features:Message.SendLimitIntervalDesc"),
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 1)));
displayName: L("Features:AppChatMessage.LimitInterval"),
description: L("Features:AppChatMessage.LimitIntervalDesc"),
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 1000)));
}
private static LocalizableString L(string name)

24
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureNames.cs

@ -18,10 +18,30 @@ public static class WeChatWorkFeatureNames
/// <summary>
/// 发送次数上限
/// </summary>
public const string SendLimit = GroupName + ".SendLimit";
public const string Limit = GroupName + ".Limit";
/// <summary>
/// 发送次数上限时长
/// </summary>
public const string SendLimitInterval = GroupName + ".SendLimitInterval";
public const string LimitInterval = GroupName + ".LimitInterval";
}
public static class AppChat
{
public const string GroupName = WeChatWorkFeatureNames.GroupName + ".AppChat";
public static class Message
{
/// <summary>
/// 启用消息推送
/// </summary>
public const string Enable = GroupName + ".Enable";
/// <summary>
/// 发送次数上限
/// </summary>
public const string Limit = GroupName + ".Limit";
/// <summary>
/// 发送次数上限时长
/// </summary>
public const string LimitInterval = GroupName + ".LimitInterval";
}
}
}

15
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/en.json

@ -7,10 +7,17 @@
"Features:Message": "WeCom message push",
"Features:MessageEnable": "Enable WeCom message push",
"Features:MessageEnableDesc": "Enable so that the app will have the ability to push messages to the app via WeCom.",
"Features:Message.SendLimit": "Restrictions on WeCom message push,",
"Features:Message.SendLimitDesc": "Set to limit the WeCom application message push limit.",
"Features:Message.SendLimitInterval": "WeCom message limit period",
"Features:Message.SendLimitIntervalDesc": "Set the limit period of WeCom messages (time scale: days). Each application cannot exceed the limit number of accounts *200 people/day.",
"Features:Message.Limit": "Restrictions on WeCom message push,",
"Features:Message.LimitDesc": "Set to limit the WeCom application message push limit.",
"Features:Message.LimitInterval": "WeCom message limit period",
"Features:Message.LimitIntervalDesc": "Set the limit period of WeCom messages (time scale: days). Each application cannot exceed the limit number of accounts *200 people/day.",
"Features:AppChatMessage": "企业微信群聊消息推送",
"Features:AppChatMessageEnable": "启用企业微信群聊消息推送",
"Features:AppChatMessageEnableDesc": "启用以使应用将拥有通过企业微信推送到群聊消息的能力.",
"Features:AppChatMessage.Limit": "企业微信群聊消息推送限制",
"Features:AppChatMessage.LimitDesc": "设置以限制企业微信群聊消息推送上限.",
"Features:AppChatMessage.LimitInterval": "企业微信群聊消息限制周期",
"Features:AppChatMessage.LimitIntervalDesc": "设置企业微信群聊消息限制周期(时间刻度: 分).每企业所有应用发送群消息不可超过2万人次/分,不可超过30万人次/小时.",
"DisplayName:WeChatWork.Connection.CorpId": "Corp Id",
"Description:WeChatWork.Connection.CorpId": "Each enterprise has a unique corpid, to obtain this information, you can view \"Enterprise ID\" under \"My Enterprise\" - \"Enterprise Information\" in the management background (requires administrator permissions).",
"DisplayName:WeChatWork.EnabledQuickLogin": "Enabled Quick Login",

19
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/zh-Hans.json

@ -4,13 +4,20 @@
"Features:WeChatWork": "企业微信",
"Features:WeChatWorkEnable": "启用企业微信",
"Features:WeChatWorkEnableDesc": "启用以使应用拥有企业微信的能力.",
"Features:Message": "企业微信消息推送",
"Features:MessageEnable": "启用企业微信消息推送",
"Features:Message": "企业微信应用消息推送",
"Features:MessageEnable": "启用企业微信应用消息推送",
"Features:MessageEnableDesc": "启用以使应用将拥有通过企业微信推送到应用消息的能力.",
"Features:Message.SendLimit": "企业微信消息推送限制",
"Features:Message.SendLimitDesc": "设置以限制企业微信应用消息推送上限.",
"Features:Message.SendLimitInterval": "企业微信消息限制周期",
"Features:Message.SendLimitIntervalDesc": "设置企业微信消息限制周期(时间刻度: 天).每应用不可超过账号上限数*200人次/天.",
"Features:Message.Limit": "企业微信应用消息推送限制",
"Features:Message.LimitDesc": "设置以限制企业微信应用消息推送上限.",
"Features:Message.LimitInterval": "企业微信应用消息限制周期",
"Features:Message.LimitIntervalDesc": "设置企业微信应用消息限制周期(时间刻度: 天).每应用不可超过账号上限数*200人次/天.",
"Features:AppChatMessage": "企业微信群聊消息推送",
"Features:AppChatMessageEnable": "启用企业微信群聊消息推送",
"Features:AppChatMessageEnableDesc": "启用以使应用将拥有通过企业微信推送到群聊消息的能力.",
"Features:AppChatMessage.Limit": "企业微信群聊消息推送限制",
"Features:AppChatMessage.LimitDesc": "设置以限制企业微信群聊消息推送上限.",
"Features:AppChatMessage.LimitInterval": "企业微信群聊消息限制周期",
"Features:AppChatMessage.LimitIntervalDesc": "设置企业微信群聊消息限制周期(时间刻度: 分).每企业所有应用发送群消息不可超过2万人次/分,不可超过30万人次/小时.",
"DisplayName:WeChatWork.Connection.CorpId": "企业Id",
"Description:WeChatWork.Connection.CorpId": "每个企业都拥有唯一的corpid,获取此信息可在管理后台“我的企业”-“企业信息”下查看“企业ID”(需要有管理员权限)",
"DisplayName:WeChatWork.EnabledQuickLogin": "启用快捷登录",

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/IWeChatWorkMediaProvider.cs

@ -1,4 +1,5 @@
using System.Threading;
using LINGYUN.Abp.WeChat.Work.Media.Models;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Content;

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/WeChatWorkImageResponse.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/Models/WeChatWorkImageResponse.cs

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace LINGYUN.Abp.WeChat.Work.Media;
namespace LINGYUN.Abp.WeChat.Work.Media.Models;
public class WeChatWorkImageResponse : WeChatWorkResponse
{
/// <summary>

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/WeChatWorkMediaRequest.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/Models/WeChatWorkMediaRequest.cs

@ -1,6 +1,6 @@
using Volo.Abp.Content;
namespace LINGYUN.Abp.WeChat.Work.Media;
namespace LINGYUN.Abp.WeChat.Work.Media.Models;
public class WeChatWorkMediaRequest
{
public string AccessToken { get; set; }

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/WeChatWorkMediaResponse.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/Models/WeChatWorkMediaResponse.cs

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace LINGYUN.Abp.WeChat.Work.Media;
namespace LINGYUN.Abp.WeChat.Work.Media.Models;
public class WeChatWorkMediaResponse : WeChatWorkResponse
{
/// <summary>

13
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Media/WeChatWorkMediaProvider.cs

@ -1,5 +1,5 @@
using LINGYUN.Abp.WeChat.Work.Token;
using Newtonsoft.Json;
using LINGYUN.Abp.WeChat.Work.Media.Models;
using LINGYUN.Abp.WeChat.Work.Token;
using System;
using System.Linq;
using System.Net.Http;
@ -36,8 +36,7 @@ public class WeChatWorkMediaProvider : IWeChatWorkMediaProvider, ISingletonDepen
cancellationToken);
if (!response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var errorResponse = JsonConvert.DeserializeObject<WeChatWorkResponse>(responseContent);
var errorResponse = await response.DeserializeObjectAsync<WeChatWorkResponse>();
errorResponse.ThrowIfNotSuccess();
}
@ -89,8 +88,7 @@ public class WeChatWorkMediaProvider : IWeChatWorkMediaProvider, ISingletonDepen
media);
using var response = await client.UploadMediaAsync(type, request, cancellationToken);
var responseContent = await response.Content.ReadAsStringAsync();
var mediaRespose = JsonConvert.DeserializeObject<WeChatWorkMediaResponse>(responseContent);
var mediaRespose = await response.DeserializeObjectAsync<WeChatWorkMediaResponse>();
mediaRespose.ThrowIfNotSuccess();
return mediaRespose;
@ -108,8 +106,7 @@ public class WeChatWorkMediaProvider : IWeChatWorkMediaProvider, ISingletonDepen
image);
using var response = await client.UploadImageAsync(request, cancellationToken);
var responseContent = await response.Content.ReadAsStringAsync();
var mediaRespose = JsonConvert.DeserializeObject<WeChatWorkImageResponse>(responseContent);
var mediaRespose = await response.DeserializeObjectAsync<WeChatWorkImageResponse>();
mediaRespose.ThrowIfNotSuccess();
return mediaRespose;

22
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageManager.cs

@ -0,0 +1,22 @@
using System.Threading;
using System.Threading.Tasks;
namespace LINGYUN.Abp.WeChat.Work.Message;
/// <summary>
/// 企业微信消息管理器
/// </summary>
public interface IWeChatWorkMessageManager
{
/// <summary>
/// 撤回应用消息
/// </summary>
/// <remarks>
/// 参考:https://developer.work.weixin.qq.com/document/path/94867
/// </remarks>
/// <param name="agentId">应用标识</param>
/// <param name="messageId">消息ID。从应用发送消息接口 <see cref="IWeChatWorkMessageSender"/> 处获得。</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<bool> ReCallMessageAsync(string agentId, string messageId, CancellationToken cancellationToken = default);
}

20
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageSender.cs

@ -1,4 +1,5 @@
using System.Threading;
using LINGYUN.Abp.WeChat.Work.Message.Response;
using System.Threading;
using System.Threading.Tasks;
namespace LINGYUN.Abp.WeChat.Work.Message;
@ -8,12 +9,27 @@ namespace LINGYUN.Abp.WeChat.Work.Message;
public interface IWeChatWorkMessageSender
{
/// <summary>
/// 发送消息
/// 发送应用消息
/// </summary>
/// <remarks>
/// 参考:https://developer.work.weixin.qq.com/document/path/90236
/// </remarks>
/// <param name="message">继承自 <see cref="WeChatWorkMessage"/> 的企业微信消息载体</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<WeChatWorkMessageResponse> SendAsync(
WeChatWorkMessage message,
CancellationToken cancellationToken = default);
/// <summary>
/// 发送群聊消息
/// </summary>
/// <remarks>
/// 参考:https://developer.work.weixin.qq.com/document/path/90248
/// </remarks>
/// <param name="message">继承自 <see cref="WeChatWorkAppChatMessage"/> 的企业微信群聊消息载体</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<WeChatWorkResponse> SendAsync(
WeChatWorkAppChatMessage message,
CancellationToken cancellationToken = default);
}

90
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/MiniProgramMessage.cs

@ -0,0 +1,90 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 小程序通知消息
/// </summary>
public class MiniProgramMessage
{
/// <summary>
/// 小程序appid,必须是与当前应用关联的小程序
/// </summary>
[NotNull]
[JsonProperty("appid")]
[JsonPropertyName("appid")]
public string AppId { get; set; }
/// <summary>
/// 消息标题,长度限制4-12个汉字(支持id转译)
/// </summary>
[NotNull]
[JsonProperty("title")]
[JsonPropertyName("title")]
public string Title { get; set; }
/// <summary>
/// 点击消息卡片后的小程序页面,最长1024个字节,仅限本小程序内的页面。该字段不填则消息点击后不跳转。
/// </summary>
[CanBeNull]
[JsonProperty("page")]
[JsonPropertyName("page")]
public string Page { get; set; }
/// <summary>
/// 消息描述,长度限制4-12个汉字(支持id转译)
/// </summary>
[CanBeNull]
[JsonProperty("description")]
[JsonPropertyName("description")]
public string Description { get; set; }
/// <summary>
/// 是否放大第一个content_item
/// </summary>
[CanBeNull]
[JsonProperty("emphasis_first_item")]
[JsonPropertyName("emphasis_first_item")]
public bool? EmphasisFirstItem { get; set; }
/// <summary>
/// 消息内容键值对,最多允许10个item
/// </summary>
[CanBeNull]
[JsonProperty("content_item")]
[JsonPropertyName("content_item")]
public List<MiniProgramContent> ContentItems{ get; set; }
public MiniProgramMessage()
{
ContentItems = new List<MiniProgramContent>();
}
public MiniProgramMessage(
string appId,
string title,
string page = null,
string description = null,
bool? emphasisFirstItem = null)
{
AppId = appId;
Page = page;
Title = title;
Description = description;
EmphasisFirstItem = emphasisFirstItem;
}
}
public class MiniProgramContent
{
/// <summary>
/// 长度10个汉字以内
/// </summary>
[NotNull]
[JsonProperty("key")]
[JsonPropertyName("key")]
public string Key { get; set; }
/// <summary>
/// 长度30个汉字以内(支持id转译)
/// </summary>
[NotNull]
[JsonProperty("value")]
[JsonPropertyName("value")]
public string Value { get; set; }
}

34
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatFileMessage.cs

@ -0,0 +1,34 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信群聊文件消息
/// </summary>
public class WeChatWorkAppChatFileMessage : WeChatWorkAppChatMessage
{
public WeChatWorkAppChatFileMessage(
string agentId,
string chatId,
MediaMessage file) : base(agentId, chatId, "file")
{
File = file;
}
/// <summary>
/// 媒体文件
/// </summary>
[NotNull]
[JsonProperty("file")]
[JsonPropertyName("file")]
public MediaMessage File { get; set; }
/// <summary>
/// 表示是否是保密消息,
/// 0表示可对外分享,
/// 1表示不能分享且内容显示水印,
/// 默认为0
/// </summary>
[JsonProperty("safe")]
[JsonPropertyName("safe")]
public byte Safe { get; set; }
}

34
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatImageMessage.cs

@ -0,0 +1,34 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信群聊图片消息
/// </summary>
public class WeChatWorkAppChatImageMessage : WeChatWorkAppChatMessage
{
public WeChatWorkAppChatImageMessage(
string agentId,
string chatId,
MediaMessage image) : base(agentId, chatId, "image")
{
Image = image;
}
/// <summary>
/// 图片媒体文件
/// </summary>
[NotNull]
[JsonProperty("image")]
[JsonPropertyName("image")]
public MediaMessage Image { get; set; }
/// <summary>
/// 表示是否是保密消息,
/// 0表示可对外分享,
/// 1表示不能分享且内容显示水印,
/// 默认为0
/// </summary>
[JsonProperty("safe")]
[JsonPropertyName("safe")]
public int Safe { get; set; }
}

34
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatMarkdownMessage.cs

@ -0,0 +1,34 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信群聊markdown消息
/// </summary>
public class WeChatWorkAppChatMarkdownMessage : WeChatWorkAppChatMessage
{
public WeChatWorkAppChatMarkdownMessage(
string agentId,
string chatId,
MarkdownMessage markdown) : base(agentId, chatId, "markdown")
{
Markdown = markdown;
}
/// <summary>
/// markdown消息
/// </summary>
[NotNull]
[JsonProperty("markdown")]
[JsonPropertyName("markdown")]
public MarkdownMessage Markdown { get; set; }
/// <summary>
/// 表示是否是保密消息,
/// 0不保密
/// 1保密
/// 默认为0
/// </summary>
[JsonProperty("safe")]
[JsonPropertyName("safe")]
public byte Safe { get; set; }
}

34
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatMpNewMessage.cs

@ -0,0 +1,34 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信群聊文本图文消息
/// </summary>
public class WeChatWorkAppChatMpNewMessage : WeChatWorkAppChatMessage
{
public WeChatWorkAppChatMpNewMessage(
string agentId,
string chatId,
MpNewMessagePayload mpnews) : base(agentId, chatId, "mpnews")
{
News = mpnews;
}
/// <summary>
/// 图文消息(mp)
/// </summary>
[NotNull]
[JsonProperty("mpnews")]
[JsonPropertyName("mpnews")]
public MpNewMessagePayload News { get; set; }
/// <summary>
/// 表示是否是保密消息,
/// 0不保密
/// 1保密
/// 默认为0
/// </summary>
[JsonProperty("safe")]
[JsonPropertyName("safe")]
public byte Safe { get; set; }
}

34
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatNewMessage.cs

@ -0,0 +1,34 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信群聊文本图文消息
/// </summary>
public class WeChatWorkAppChatNewMessage : WeChatWorkAppChatMessage
{
public WeChatWorkAppChatNewMessage(
string agentId,
string chatId,
NewMessagePayload news) : base(agentId, chatId, "news")
{
News = news;
}
/// <summary>
/// 图文消息
/// </summary>
[NotNull]
[JsonProperty("news")]
[JsonPropertyName("news")]
public NewMessagePayload News { get; set; }
/// <summary>
/// 表示是否是保密消息,
/// 0不保密
/// 1保密
/// 默认为0
/// </summary>
[JsonProperty("safe")]
[JsonPropertyName("safe")]
public byte Safe { get; set; }
}

34
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatTextCardMessage.cs

@ -0,0 +1,34 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信群聊文本卡片消息
/// </summary>
public class WeChatWorkAppChatTextCardMessage : WeChatWorkAppChatMessage
{
public WeChatWorkAppChatTextCardMessage(
string agentId,
string chatId,
TextCardMessage textcard) : base(agentId, chatId, "textcard")
{
TextCard = textcard;
}
/// <summary>
/// 卡片消息
/// </summary>
[NotNull]
[JsonProperty("textcard")]
[JsonPropertyName("textcard")]
public TextCardMessage TextCard { get; set; }
/// <summary>
/// 表示是否是保密消息,
/// 0表示可对外分享,
/// 1表示不能分享且内容显示水印,
/// 默认为0
/// </summary>
[JsonProperty("safe")]
[JsonPropertyName("safe")]
public byte Safe { get; set; }
}

35
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatTextMessage.cs

@ -0,0 +1,35 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信群聊文本消息
/// </summary>
public class WeChatWorkAppChatTextMessage : WeChatWorkAppChatMessage
{
public WeChatWorkAppChatTextMessage(
string agentId,
string chatId,
TextMessage text) : base(agentId, chatId, "text")
{
Text = text;
}
/// <summary>
/// 消息内容,最长不超过2048个字节,超过将截断(支持id转译)
/// </summary>
[NotNull]
[JsonProperty("text")]
[JsonPropertyName("text")]
public TextMessage Text { get; set; }
/// <summary>
/// 表示是否是保密消息,
/// 0表示可对外分享,
/// 1表示不能分享且内容显示水印,
/// 默认为0
/// </summary>
[JsonProperty("safe")]
[JsonPropertyName("safe")]
public int Safe { get; set; }
}

34
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatVideoMessage.cs

@ -0,0 +1,34 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信群聊语言消息
/// </summary>
public class WeChatWorkAppChatVideoMessage : WeChatWorkAppChatMessage
{
public WeChatWorkAppChatVideoMessage(
string agentId,
string chatId,
VideoMessage video) : base(agentId, chatId, "video")
{
Video = video;
}
/// <summary>
/// 视频媒体文件
/// </summary>
[NotNull]
[JsonProperty("video")]
[JsonPropertyName("video")]
public VideoMessage Video { get; set; }
/// <summary>
/// 表示是否是保密消息,
/// 0表示可对外分享,
/// 1表示不能分享且内容显示水印,
/// 默认为0
/// </summary>
[JsonProperty("safe")]
[JsonPropertyName("safe")]
public byte Safe { get; set; }
}

25
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatVoiceMessage.cs

@ -0,0 +1,25 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信群聊语言消息
/// </summary>
public class WeChatWorkAppChatVoiceMessage : WeChatWorkAppChatMessage
{
public WeChatWorkAppChatVoiceMessage(
string agentId,
string chatId,
MediaMessage voice) : base(agentId, chatId, "voice")
{
Voice = voice;
}
/// <summary>
/// 语音媒体文件
/// </summary>
[NotNull]
[JsonProperty("voice")]
[JsonPropertyName("voice")]
public MediaMessage Voice { get; set; }
}

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkFileMessage.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkFileMessage.cs

@ -1,9 +1,8 @@
using JetBrains.Annotations;
using LINGYUN.Abp.WeChat.Work.Message.Models;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信文件消息
/// </summary>

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkImageMessage.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkImageMessage.cs

@ -1,9 +1,8 @@
using JetBrains.Annotations;
using LINGYUN.Abp.WeChat.Work.Message.Models;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信图片消息
/// </summary>

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMarkdownMessage.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMarkdownMessage.cs

@ -1,9 +1,8 @@
using JetBrains.Annotations;
using LINGYUN.Abp.WeChat.Work.Message.Models;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信markdown消息
/// </summary>

84
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMiniProgramMessage.cs

@ -0,0 +1,84 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信小程序通知消息
/// </summary>
public class WeChatWorkMiniProgramMessage
{
/// <summary>
/// 指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个)。
/// 特殊情况:指定为"@all",则向该企业应用的全部成员发送
/// </summary>
[JsonProperty("touser")]
[JsonPropertyName("touser")]
public virtual string ToUser { get; set; }
/// <summary>
/// 指定接收消息的部门,部门ID列表,多个接收者用‘|’分隔,最多支持100个。
/// 当touser为"@all"时忽略本参数
/// </summary>
[JsonProperty("toparty")]
[JsonPropertyName("toparty")]
public virtual string ToParty { get; set; }
/// <summary>
/// 指定接收消息的标签,标签ID列表,多个接收者用‘|’分隔,最多支持100个。
/// 当touser为"@all"时忽略本参数
/// </summary>
[JsonProperty("totag")]
[JsonPropertyName("totag")]
public virtual string ToTag { get; set; }
/// <summary>
/// 消息类型
/// </summary>
[NotNull]
[JsonProperty("msgtype")]
[JsonPropertyName("msgtype")]
public virtual string MsgType { get; }
/// <summary>
/// 表示是否开启id转译,0表示否,1表示是,默认0。
/// 仅第三方应用需要用到
/// 企业自建应用可以忽略。
/// </summary>
[JsonProperty("enable_id_trans")]
[JsonPropertyName("enable_id_trans")]
public byte EnableIdTrans { get; set; }
/// <summary>
/// 表示是否开启重复消息检查,0表示否,1表示是,默认0
/// </summary>
[JsonProperty("enable_duplicate_check")]
[JsonPropertyName("enable_duplicate_check")]
public byte EnableDuplicateCheck { get; set; }
/// <summary>
/// 表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时
/// </summary>
[JsonProperty("duplicate_check_interval")]
[JsonPropertyName("duplicate_check_interval")]
public int DuplicateCheckInterval { get; set; } = 1800;
/// <summary>
/// 消息内容
/// </summary>
[NotNull]
[JsonProperty("miniprogram_notice")]
[JsonPropertyName("miniprogram_notice")]
public MiniProgramMessage MiniProgram { get; set; }
public WeChatWorkMiniProgramMessage(
MiniProgramMessage miniProgram,
string toUser = "",
string toParty = "",
string toTag = "",
byte enableIdTrans = 0,
byte enableDuplicateCheck = 0,
int duplicateCheckInterval = 1800)
{
ToUser = toUser;
ToParty = toParty;
ToTag = toTag;
EnableIdTrans = enableIdTrans;
EnableDuplicateCheck = enableDuplicateCheck;
DuplicateCheckInterval = duplicateCheckInterval;
MiniProgram = miniProgram;
MsgType = "miniprogram_notice";
}
}

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMpNewMessage.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMpNewMessage.cs

@ -1,9 +1,8 @@
using JetBrains.Annotations;
using LINGYUN.Abp.WeChat.Work.Message.Models;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信文本图文消息
/// </summary>

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkNewMessage.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkNewMessage.cs

@ -1,9 +1,8 @@
using JetBrains.Annotations;
using LINGYUN.Abp.WeChat.Work.Message.Models;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信文本图文消息
/// </summary>

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkTextCardMessage.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkTextCardMessage.cs

@ -1,9 +1,8 @@
using JetBrains.Annotations;
using LINGYUN.Abp.WeChat.Work.Message.Models;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信文本卡片消息
/// </summary>

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkTextMessage.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkTextMessage.cs

@ -1,9 +1,8 @@
using JetBrains.Annotations;
using LINGYUN.Abp.WeChat.Work.Message.Models;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信文本消息
/// </summary>

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkVideoMessage.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkVideoMessage.cs

@ -1,9 +1,8 @@
using JetBrains.Annotations;
using LINGYUN.Abp.WeChat.Work.Message.Models;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信语言消息
/// </summary>

3
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkVoiceMessage.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkVoiceMessage.cs

@ -1,9 +1,8 @@
using JetBrains.Annotations;
using LINGYUN.Abp.WeChat.Work.Message.Models;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message;
namespace LINGYUN.Abp.WeChat.Work.Message.Models;
/// <summary>
/// 企业微信语言消息
/// </summary>

27
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Request/WeChatWorkMessageReCallRequest.cs

@ -0,0 +1,27 @@
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Request;
/// <summary>
/// 撤回消息请求载体
/// </summary>
public class WeChatWorkMessageReCallRequest : WeChatWorkRequest
{
/// <summary>
/// 调用接口凭证
/// </summary>
[System.Text.Json.Serialization.JsonIgnore]
[Newtonsoft.Json.JsonIgnore]
public string AccessToken { get; set; }
/// <summary>
/// 消息ID
/// </summary>
[JsonProperty("msgid")]
[JsonPropertyName("msgid")]
public string MessageId { get; set; }
public WeChatWorkMessageReCallRequest(string accessToken, string messageId)
{
AccessToken = accessToken;
MessageId = messageId;
}
}

11
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Request/WeChatWorkMessageRequest.cs

@ -0,0 +1,11 @@
namespace LINGYUN.Abp.WeChat.Work.Message.Request;
public class WeChatWorkMessageRequest<TMessage>
{
public string AccessToken { get; set; }
public TMessage Message { get; set; }
public WeChatWorkMessageRequest(string accessToken, TMessage message)
{
AccessToken = accessToken;
Message = message;
}
}

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageResponse.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Response/WeChatWorkMessageResponse.cs

@ -1,7 +1,7 @@
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message;
namespace LINGYUN.Abp.WeChat.Work.Message.Response;
/// <summary>
/// 企业微信发送消息响应
/// </summary>

28
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCard.cs

@ -0,0 +1,28 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
public abstract class TemplateCard
{
/// <summary>
/// 模板卡片类型
/// </summary>
[NotNull]
[JsonProperty("card_type")]
[JsonPropertyName("card_type")]
public string Type { get; }
/// <summary>
/// 任务id,同一个应用任务id不能重复,只能由数字、字母和“_-@”组成,最长128字节
/// </summary>
[CanBeNull]
[JsonProperty("task_id")]
[JsonPropertyName("task_id")]
public string TaskId { get; set; }
protected TemplateCard(string type, string taskId = "")
{
Type = type;
TaskId = taskId;
}
}

31
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardAction.cs

@ -0,0 +1,31 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
/// <summary>
/// 卡片操作按钮
/// </summary>
public class TemplateCardAction
{
public TemplateCardAction(string key, string text)
{
Key = key;
Text = text;
}
/// <summary>
/// 操作key值,用户点击后,会产生回调事件将本参数作为EventKey返回,回调事件会带上该key值,最长支持1024字节,不可重复
/// </summary>
[NotNull]
[JsonProperty("key")]
[JsonPropertyName("key")]
public string Key { get; set; }
/// <summary>
/// 操作的描述文案
/// </summary>
[NotNull]
[JsonProperty("text")]
[JsonPropertyName("text")]
public string Text { get; set; }
}

31
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardActionMenu.cs

@ -0,0 +1,31 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
/// <summary>
/// 卡片右上角更多操作按钮
/// </summary>
public class TemplateCardActionMenu
{
/// <summary>
/// 卡片副交互辅助文本说明
/// </summary>
[CanBeNull]
[JsonProperty("desc")]
[JsonPropertyName("desc")]
public string Description { get; set; }
/// <summary>
/// 操作列表,列表长度取值范围为 [1, 3]
/// </summary>
[NotNull]
[JsonProperty("action_list")]
[JsonPropertyName("action_list")]
public List<TemplateCardAction> Actions { get; set;}
public TemplateCardActionMenu(List<TemplateCardAction> actions, string description = "")
{
Actions = actions;
Description = description;
}
}

50
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardCardAction.cs

@ -0,0 +1,50 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
/// <summary>
/// 整体卡片的点击跳转事件
/// </summary>
public class TemplateCardCardAction
{
public TemplateCardCardAction(string url)
{
Type = 1;
Url = url;
}
public TemplateCardCardAction(string appid, string pagePath)
{
Type = 2;
AppId = appid;
PagePath = pagePath;
}
/// <summary>
/// 跳转链接类型,0或不填代表不是链接,1 代表跳转url,2 代表跳转小程序
/// </summary>
[CanBeNull]
[JsonProperty("type")]
[JsonPropertyName("type")]
public byte Type { get; set; }
/// <summary>
/// 跳转链接的url,card_action.type是1时必填
/// </summary>
[CanBeNull]
[JsonProperty("url")]
[JsonPropertyName("url")]
public string Url { get; set; }
/// <summary>
/// 跳转链接的小程序的appid,必须是与当前应用关联的小程序,card_action.type是2时必填
/// </summary>
[CanBeNull]
[JsonProperty("appid")]
[JsonPropertyName("appid")]
public string AppId { get; set; }
/// <summary>
/// 跳转链接的小程序的pagepath,card_action.type是2时选填
/// </summary>
[CanBeNull]
[JsonProperty("pagepath")]
[JsonPropertyName("pagepath")]
public string PagePath { get; set; }
}

33
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardEmphasisContent.cs

@ -0,0 +1,33 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
/// <summary>
/// 关键数据样式
/// </summary>
public class TemplateCardEmphasisContent
{
public TemplateCardEmphasisContent(
string title = "",
string description = "")
{
Title = title;
Description = description;
}
/// <summary>
/// 关键数据样式的数据内容,建议不超过14个字
/// </summary>
[CanBeNull]
[JsonProperty("title")]
[JsonPropertyName("title")]
public string Title { get; set; }
/// <summary>
/// 关键数据样式的数据描述内容,建议不超过22个字
/// </summary>
[CanBeNull]
[JsonProperty("desc")]
[JsonPropertyName("desc")]
public string Description { get; set; }
}

93
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardHorizontalContent.cs

@ -0,0 +1,93 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
/// <summary>
/// 二级标题+文本
/// </summary>
public class TemplateCardHorizontalContent
{
public static TemplateCardHorizontalContent None(string keyName, string value = "")
{
return new TemplateCardHorizontalContent(
keyName, 0, value);
}
public static TemplateCardHorizontalContent FromUrl(string keyName, string url, string value = "")
{
return new TemplateCardHorizontalContent(
keyName, 1, value, url);
}
public static TemplateCardHorizontalContent FromMedia(string keyName, string mediaId, string value = "")
{
return new TemplateCardHorizontalContent(
keyName, 2, value, mediaId: mediaId);
}
public static TemplateCardHorizontalContent FromUser(string keyName, string userId, string value = "")
{
return new TemplateCardHorizontalContent(
keyName, 3, value, userId: userId);
}
public TemplateCardHorizontalContent(
string keyName,
byte type = 0,
string value = "",
string url = "",
string mediaId = "",
string userId = "")
{
Type = type;
KeyName = keyName;
Value = value;
Url = url;
MediaId = mediaId;
UserId = userId;
}
/// <summary>
/// 链接类型,0或不填代表不是链接,1 代表跳转url,2 代表下载附件,3 代表点击跳转成员详情
/// </summary>
[CanBeNull]
[JsonProperty("type")]
[JsonPropertyName("type")]
public byte Type { get; }
/// <summary>
/// 二级标题,建议不超过5个字
/// </summary>
[NotNull]
[JsonProperty("keyname")]
[JsonPropertyName("keyname")]
public string KeyName { get; set; }
/// <summary>
/// 二级文本,如果horizontal_content_list.type是2,该字段代表文件名称(要包含文件类型),建议不超过30个字,(支持id转译)
/// </summary>
[CanBeNull]
[JsonProperty("value")]
[JsonPropertyName("value")]
public string Value { get; set; }
/// <summary>
/// 链接跳转的url,horizontal_content_list.type是1时必填
/// </summary>
[CanBeNull]
[JsonProperty("url")]
[JsonPropertyName("url")]
public string Url { get; set; }
/// <summary>
/// 附件的media_id,horizontal_content_list.type是2时必填
/// </summary>
[CanBeNull]
[JsonProperty("media_id")]
[JsonPropertyName("media_id")]
public string MediaId { get; set; }
/// <summary>
/// 成员详情的userid,horizontal_content_list.type是3时必填
/// </summary>
[CanBeNull]
[JsonProperty("userid")]
[JsonPropertyName("userid")]
public string UserId { get; set; }
}

62
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardJump.cs

@ -0,0 +1,62 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
/// <summary>
/// 跳转指引样式
/// </summary>
public class TemplateCardJump
{
public TemplateCardJump(string title, string url)
{
Type = 1;
Url = url;
Title = title;
}
public TemplateCardJump(string title, string appid, string pagePath)
{
Type = 2;
AppId = appid;
PagePath = pagePath;
Title = title;
}
/// <summary>
/// 跳转链接类型,0或不填代表不是链接,1 代表跳转url,2 代表跳转小程序
/// </summary>
[CanBeNull]
[JsonProperty("type")]
[JsonPropertyName("type")]
public byte Type { get; }
/// <summary>
/// 跳转链接样式的文案内容,建议不超过18个字
/// </summary>
[NotNull]
[JsonProperty("title")]
[JsonPropertyName("title")]
public string Title { get; set; }
/// <summary>
/// 跳转链接的url,jump_list.type是1时必填
/// </summary>
[CanBeNull]
[JsonProperty("url")]
[JsonPropertyName("url")]
public string Url { get; set; }
/// <summary>
/// 跳转链接的小程序的appid,必须是与当前应用关联的小程序,jump_list.type是2时必填
/// </summary>
[CanBeNull]
[JsonProperty("appid")]
[JsonPropertyName("appid")]
public string AppId { get; set; }
/// <summary>
/// 跳转链接的小程序的pagepath,jump_list.type是2时选填
/// </summary>
[CanBeNull]
[JsonProperty("pagepath")]
[JsonPropertyName("pagepath")]
public string PagePath { get; set; }
}

33
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardMainTitle.cs

@ -0,0 +1,33 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
/// <summary>
/// 卡票标题
/// </summary>
public class TemplateCardMainTitle
{
public TemplateCardMainTitle(
string title = "",
string description = "")
{
Title = title;
Description = description;
}
/// <summary>
/// 一级标题,建议不超过36个字,文本通知型卡片本字段非必填,但不可本字段和sub_title_text都不填,(支持id转译)
/// </summary>
[CanBeNull]
[JsonProperty("title")]
[JsonPropertyName("title")]
public string Title { get; set; }
/// <summary>
/// 标题辅助信息,建议不超过44个字,(支持id转译)
/// </summary>
[CanBeNull]
[JsonProperty("desc")]
[JsonPropertyName("desc")]
public string Description { get; set; }
}

68
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardQuoteArea.cs

@ -0,0 +1,68 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
/// <summary>
/// 引用文献样式
/// </summary>
public class TemplateCardQuoteArea
{
public TemplateCardQuoteArea(string url, string title = "", string text = "")
{
Type = 1;
Url = url;
Title = title;
Text = text;
}
public TemplateCardQuoteArea(string appid, string pagePath, string title = "", string text = "")
{
Type = 2;
AppId = appid;
PagePath = pagePath;
Title = title;
Text = text;
}
/// <summary>
/// 引用文献样式区域点击事件,0或不填代表没有点击事件,1 代表跳转url,2 代表跳转小程序
/// </summary>
[CanBeNull]
[JsonProperty("type")]
[JsonPropertyName("type")]
public byte Type { get; }
/// <summary>
/// 点击跳转的url,quote_area.type是1时必填
/// </summary>
[CanBeNull]
[JsonProperty("url")]
[JsonPropertyName("url")]
public string Url { get; set; }
/// <summary>
/// 点击跳转的小程序的appid,必须是与当前应用关联的小程序,quote_area.type是2时必填
/// </summary>
[CanBeNull]
[JsonProperty("appid")]
[JsonPropertyName("appid")]
public string AppId { get; set; }
/// <summary>
/// 点击跳转的小程序的pagepath,quote_area.type是2时选填
/// </summary>
[CanBeNull]
[JsonProperty("pagepath")]
[JsonPropertyName("pagepath")]
public string PagePath { get; set; }
/// <summary>
/// 引用文献样式的标题
/// </summary>
[CanBeNull]
[JsonProperty("title")]
[JsonPropertyName("title")]
public string Title { get; set; }
/// <summary>
/// 引用文献样式的引用文案
/// </summary>
[CanBeNull]
[JsonProperty("quote_text")]
[JsonPropertyName("quote_text")]
public string Text { get; set; }
}

52
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardSource.cs

@ -0,0 +1,52 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
/// <summary>
/// 来源文字颜色
/// </summary>
public enum DescriptionColor
{
Gray = 0,
Black = 1,
Red = 2,
Green = 3,
}
/// <summary>
/// 卡片来源样式信息
/// </summary>
public class TemplateCardSource
{
public TemplateCardSource(
string iconUrl = "",
string description = "",
DescriptionColor descriptionColor = DescriptionColor.Gray)
{
IconUrl = iconUrl;
Description = description;
DescriptionColor = descriptionColor;
}
/// <summary>
/// 来源图片的url,来源图片的尺寸建议为72*72
/// </summary>
[CanBeNull]
[JsonProperty("icon_url")]
[JsonPropertyName("icon_url")]
public string IconUrl { get; set; }
/// <summary>
/// 来源图片的描述,建议不超过20个字,(支持id转译)
/// </summary>
[CanBeNull]
[JsonProperty("desc")]
[JsonPropertyName("desc")]
public string Description { get; set; }
/// <summary>
/// 来源文字的颜色,目前支持:0(默认) 灰色,1 黑色,2 红色,3 绿色
/// </summary>
[CanBeNull]
[JsonProperty("desc_color")]
[JsonPropertyName("desc_color")]
public DescriptionColor DescriptionColor { get; set; }
}

81
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TextTemplateCard.cs

@ -0,0 +1,81 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
/// <summary>
/// 文本模板卡片消息
/// </summary>
public class TextTemplateCard : TemplateCard
{
public TextTemplateCard(TemplateCardCardAction cardAction, string taskId = "")
: base("template_card", taskId)
{
CardAction = cardAction;
}
/// <summary>
/// 卡片来源样式信息,不需要来源样式可不填写
/// </summary>
[CanBeNull]
[JsonProperty("source")]
[JsonPropertyName("source")]
public TemplateCardSource Source { get; set; }
/// <summary>
/// 卡片右上角更多操作按钮
/// </summary>
[CanBeNull]
[JsonProperty("action_menu")]
[JsonPropertyName("action_menu")]
public TemplateCardActionMenu ActionMenu { get; set; }
/// <summary>
/// 一级标题
/// </summary>
[CanBeNull]
[JsonProperty("main_title")]
[JsonPropertyName("main_title")]
public TemplateCardMainTitle MainTitle { get; set; }
/// <summary>
/// 二级普通文本,建议不超过160个字,(支持id转译)
/// </summary>
[CanBeNull]
[JsonProperty("sub_title_text")]
[JsonPropertyName("sub_title_text")]
public string SubTitle { get; set; }
/// <summary>
/// 引用文献样式
/// </summary>
[CanBeNull]
[JsonProperty("quote_area")]
[JsonPropertyName("quote_area")]
public TemplateCardQuoteArea QuoteArea { get; set; }
/// <summary>
/// 关键数据样式
/// </summary>
[CanBeNull]
[JsonProperty("emphasis_content")]
[JsonPropertyName("emphasis_content")]
public TemplateCardEmphasisContent EmphasisContent { get; set; }
/// <summary>
/// 二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6
/// </summary>
[CanBeNull]
[JsonProperty("horizontal_content_list")]
[JsonPropertyName("horizontal_content_list")]
public List<TemplateCardHorizontalContent> HorizontalContents { get; set; }
/// <summary>
/// 跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3
/// </summary>
[CanBeNull]
[JsonProperty("jump_list")]
[JsonPropertyName("jump_list")]
public List<TemplateCardJump> Jumps { get; set; }
/// <summary>
/// 整体卡片的点击跳转事件,text_notice必填本字段
/// </summary>
[NotNull]
[JsonProperty("TemplateCardCardAction")]
[JsonPropertyName("TemplateCardCardAction")]
public TemplateCardCardAction CardAction { get; set; }
}

47
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/WeChatWorkTemplateCardMessage.cs

@ -0,0 +1,47 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message.Templates;
/// <summary>
/// 企业微信模板卡片消息
/// </summary>
public class WeChatWorkTemplateCardMessage : WeChatWorkMessage
{
public WeChatWorkTemplateCardMessage(
string agentId,
TemplateCard template,
string toUser = "",
string toParty = "",
string toTag = "") : base(agentId, "template_card", toUser, toParty, toTag)
{
Template = template;
}
/// <summary>
/// 模板卡片消息
/// </summary>
[NotNull]
[JsonProperty("template_card")]
[JsonPropertyName("template_card")]
public TemplateCard Template { get; set; }
/// <summary>
/// 表示是否开启id转译,0表示否,1表示是,默认0。
/// 仅第三方应用需要用到
/// 企业自建应用可以忽略。
/// </summary>
[JsonProperty("enable_id_trans")]
[JsonPropertyName("enable_id_trans")]
public byte EnableIdTrans { get; set; }
/// <summary>
/// 表示是否开启重复消息检查,0表示否,1表示是,默认0
/// </summary>
[JsonProperty("enable_duplicate_check")]
[JsonPropertyName("enable_duplicate_check")]
public byte EnableDuplicateCheck { get; set; }
/// <summary>
/// 表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时
/// </summary>
[JsonProperty("duplicate_check_interval")]
[JsonPropertyName("duplicate_check_interval")]
public int DuplicateCheckInterval { get; set; } = 1800;
}

45
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkAppChatMessage.cs

@ -0,0 +1,45 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work.Message;
/// <summary>
/// 企业微信群聊消息
/// </summary>
public abstract class WeChatWorkAppChatMessage : WeChatWorkRequest
{
protected WeChatWorkAppChatMessage(
string agentId,
string chatId,
string msgType)
{
AgentId = agentId;
ChatId = chatId;
MsgType = msgType;
}
/// <summary>
/// 群聊id
/// </summary>
[NotNull]
[JsonProperty("chatid")]
[JsonPropertyName("chatid")]
public virtual string ChatId { get; protected set; }
/// <summary>
/// 消息类型
/// </summary>
[NotNull]
[JsonProperty("msgtype")]
[JsonPropertyName("msgtype")]
public virtual string MsgType { get; protected set; }
/// <summary>
/// 企业应用的id
/// </summary>
/// <remarks>
/// 由于需要换取token, 因此需要传递应用标识
/// </remarks>
[NotNull]
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public virtual string AgentId { get; protected set; }
}

11
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessage.cs

@ -6,7 +6,7 @@ namespace LINGYUN.Abp.WeChat.Work.Message;
/// <summary>
/// 企业微信消息
/// </summary>
public abstract class WeChatWorkMessage
public abstract class WeChatWorkMessage : WeChatWorkRequest
{
/// <summary>
/// 指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个)。
@ -48,8 +48,8 @@ public abstract class WeChatWorkMessage
protected WeChatWorkMessage(
string agentId,
string msgType,
string toUser = "",
string toParty = "",
string toUser = "",
string toParty = "",
string toTag = "")
{
AgentId = agentId;
@ -58,9 +58,4 @@ public abstract class WeChatWorkMessage
ToParty = toParty;
ToTag = toTag;
}
public virtual string SerializeToJson()
{
return JsonConvert.SerializeObject(this);
}
}

43
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageManager.cs

@ -0,0 +1,43 @@
using LINGYUN.Abp.WeChat.Work.Message.Request;
using LINGYUN.Abp.WeChat.Work.Token;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.WeChat.Work.Message;
public class WeChatWorkMessageManager : IWeChatWorkMessageManager, ISingletonDependency
{
public ILogger<WeChatWorkMessageManager> Logger { get; set; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IWeChatWorkTokenProvider WeChatWorkTokenProvider { get; }
public WeChatWorkMessageManager(
IHttpClientFactory httpClientFactory,
IWeChatWorkTokenProvider weChatWorkTokenProvider)
{
HttpClientFactory = httpClientFactory;
WeChatWorkTokenProvider = weChatWorkTokenProvider;
Logger = NullLogger<WeChatWorkMessageManager>.Instance;
}
public async virtual Task<bool> ReCallMessageAsync(string agentId, string messageId, CancellationToken cancellationToken = default)
{
var token = await WeChatWorkTokenProvider.GetTokenAsync(agentId, cancellationToken);
var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient);
var request = new WeChatWorkMessageReCallRequest(
token.AccessToken,
messageId);
using var response = await client.ReCallMessageAsync(request, cancellationToken);
var messageResponse = await response.DeserializeObjectAsync<WeChatWorkResponse>();
return messageResponse.IsSuccessed;
}
}

11
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageRequest.cs

@ -1,11 +0,0 @@
namespace LINGYUN.Abp.WeChat.Work.Message;
public class WeChatWorkMessageRequest
{
public string AccessToken { get; set; }
public WeChatWorkMessage Message { get; set; }
public WeChatWorkMessageRequest(string accessToken, WeChatWorkMessage message)
{
AccessToken = accessToken;
Message = message;
}
}

38
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageSender.cs

@ -1,9 +1,10 @@
using LINGYUN.Abp.Features.LimitValidation;
using LINGYUN.Abp.WeChat.Work.Features;
using LINGYUN.Abp.WeChat.Work.Message.Request;
using LINGYUN.Abp.WeChat.Work.Message.Response;
using LINGYUN.Abp.WeChat.Work.Token;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Newtonsoft.Json;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
@ -32,22 +33,47 @@ public class WeChatWorkMessageSender : IWeChatWorkMessageSender, ISingletonDepen
[RequiresFeature(WeChatWorkFeatureNames.Message.Enable)]
[RequiresLimitFeature(
WeChatWorkFeatureNames.Message.SendLimit,
WeChatWorkFeatureNames.Message.SendLimitInterval,
WeChatWorkFeatureNames.Message.Limit,
WeChatWorkFeatureNames.Message.LimitInterval,
LimitPolicy.Days)]
public async virtual Task<WeChatWorkMessageResponse> SendAsync(WeChatWorkMessage message, CancellationToken cancellationToken = default)
{
var token = await WeChatWorkTokenProvider.GetTokenAsync(message.AgentId, cancellationToken);
var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient);
var request = new WeChatWorkMessageRequest(
var request = new WeChatWorkMessageRequest<WeChatWorkMessage>(
token.AccessToken,
message);
using var response = await client.SendMessageAsync(request, cancellationToken);
var responseContent = await response.Content.ReadAsStringAsync();
var messageResponse = await response.DeserializeObjectAsync<WeChatWorkMessageResponse>();
if (!messageResponse.IsSuccessed)
{
Logger.LogWarning("Send wechat work message failed");
Logger.LogWarning($"Error code: {messageResponse.ErrorCode}, message: {messageResponse.ErrorMessage}");
}
return messageResponse;
}
[RequiresFeature(WeChatWorkFeatureNames.AppChat.Message.Enable)]
[RequiresLimitFeature(
WeChatWorkFeatureNames.AppChat.Message.Limit,
WeChatWorkFeatureNames.AppChat.Message.LimitInterval,
LimitPolicy.Minute)]
public async virtual Task<WeChatWorkResponse> SendAsync(WeChatWorkAppChatMessage message, CancellationToken cancellationToken = default)
{
var token = await WeChatWorkTokenProvider.GetTokenAsync(message.AgentId, cancellationToken);
var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient);
var request = new WeChatWorkMessageRequest<WeChatWorkAppChatMessage>(
token.AccessToken,
message);
using var response = await client.SendMessageAsync(request, cancellationToken);
var messageResponse = await response.DeserializeObjectAsync<WeChatWorkResponse>();
var messageResponse = JsonConvert.DeserializeObject<WeChatWorkMessageResponse>(responseContent);
if (!messageResponse.IsSuccessed)
{
Logger.LogWarning("Send wechat work message failed");

4
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/IWeChatWorkCryptoService.cs

@ -1,4 +1,6 @@
namespace LINGYUN.Abp.WeChat.Work.Security;
using LINGYUN.Abp.WeChat.Work.Security.Models;
namespace LINGYUN.Abp.WeChat.Work.Security;
/// <summary>
/// 企业微信加解密接口
/// </summary>

12
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoData.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoData.cs

@ -1,4 +1,4 @@
namespace LINGYUN.Abp.WeChat.Work.Security;
namespace LINGYUN.Abp.WeChat.Work.Security.Models;
public class WeChatWorkCryptoData
{
public string ReceiveId { get; }
@ -8,11 +8,11 @@ public class WeChatWorkCryptoData
public string TimeStamp { get; }
public string Nonce { get; }
public WeChatWorkCryptoData(
string receiveId,
string token,
string encodingAESKey,
string msgSignature,
string timeStamp,
string receiveId,
string token,
string encodingAESKey,
string msgSignature,
string timeStamp,
string nonce)
{
ReceiveId = receiveId;

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoDecryptData.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoDecryptData.cs

@ -1,4 +1,4 @@
namespace LINGYUN.Abp.WeChat.Work.Security;
namespace LINGYUN.Abp.WeChat.Work.Security.Models;
public class WeChatWorkCryptoDecryptData : WeChatWorkCryptoData
{
public string PostData { get; }

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoEchoData.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoEchoData.cs

@ -1,4 +1,4 @@
namespace LINGYUN.Abp.WeChat.Work.Security;
namespace LINGYUN.Abp.WeChat.Work.Security.Models;
public class WeChatWorkCryptoEchoData : WeChatWorkCryptoData
{
public string EchoStr { get; }

4
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoService.cs

@ -1,7 +1,9 @@
using LINGYUN.Abp.WeChat.Work.Utils;
using LINGYUN.Abp.WeChat.Work.Security.Models;
using LINGYUN.Abp.WeChat.Work.Utils;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.WeChat.Work.Security;
public class WeChatWorkCryptoService : IWeChatWorkCryptoService, ISingletonDependency
{
public string Decrypt(WeChatWorkCryptoDecryptData data)

35
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/IWeChatWorkTokenProvider.cs

@ -1,11 +1,32 @@
using System.Threading;
using LINGYUN.Abp.WeChat.Work.Token.Models;
using System.Threading;
using System.Threading.Tasks;
namespace LINGYUN.Abp.WeChat.Work.Token
namespace LINGYUN.Abp.WeChat.Work.Token;
/// <summary>
/// 企业微信AccessToken接口
/// </summary>
public interface IWeChatWorkTokenProvider
{
public interface IWeChatWorkTokenProvider
{
Task<WeChatWorkToken> GetTokenAsync(string agentId, CancellationToken cancellationToken = default);
Task<WeChatWorkToken> GetTokenAsync(string corpId, string agentId, CancellationToken cancellationToken = default);
}
/// <summary>
/// 获取应用Token
/// </summary>
/// <remarks>
/// 参考:https://developer.work.weixin.qq.com/document/path/91039
/// </remarks>
/// <param name="agentId">应用标识</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<WeChatWorkToken> GetTokenAsync(string agentId, CancellationToken cancellationToken = default);
/// <summary>
/// 获取应用Token
/// </summary>
/// <remarks>
/// 参考:https://developer.work.weixin.qq.com/document/path/91039
/// </remarks>
/// <param name="corpId">企业标识</param>
/// <param name="agentId">应用标识</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<WeChatWorkToken> GetTokenAsync(string corpId, string agentId, CancellationToken cancellationToken = default);
}

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/WeChatWorkToken.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkToken.cs

@ -1,4 +1,4 @@
namespace LINGYUN.Abp.WeChat.Work.Token
namespace LINGYUN.Abp.WeChat.Work.Token.Models
{
/// <summary>
/// 企业微信令牌

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/WeChatWorkTokenCacheItem.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkTokenCacheItem.cs

@ -1,4 +1,4 @@
namespace LINGYUN.Abp.WeChat.Work.Token
namespace LINGYUN.Abp.WeChat.Work.Token.Models
{
public class WeChatWorkTokenCacheItem
{

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/WeChatWorkTokenRequest.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkTokenRequest.cs

@ -1,4 +1,4 @@
namespace LINGYUN.Abp.WeChat.Work.Token
namespace LINGYUN.Abp.WeChat.Work.Token.Models
{
public class WeChatWorkTokenRequest
{

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/WeChatWorkTokenResponse.cs → aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/Models/WeChatWorkTokenResponse.cs

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace LINGYUN.Abp.WeChat.Work.Token
namespace LINGYUN.Abp.WeChat.Work.Token.Models
{
/// <summary>
/// 微信访问令牌返回对象

201
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Token/WeChatWorkTokenProvider.cs

@ -1,9 +1,10 @@
using LINGYUN.Abp.WeChat.Work.Settings;
using LINGYUN.Abp.WeChat.Work.Token.Models;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading;
@ -13,96 +14,154 @@ using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace LINGYUN.Abp.WeChat.Work.Token
namespace LINGYUN.Abp.WeChat.Work.Token;
public class WeChatWorkTokenProvider : IWeChatWorkTokenProvider, ISingletonDependency
{
public class WeChatWorkTokenProvider : IWeChatWorkTokenProvider, ISingletonDependency
public ILogger<WeChatWorkTokenProvider> Logger { get; set; }
protected ISettingProvider SettingProvider { get; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IMemoryCache MemoryCache { get; }
protected IDistributedCache<WeChatWorkTokenCacheItem> WeChatWorkTokenCache { get; }
protected WeChatWorkOptions WeChatWorkOptions { get; }
public WeChatWorkTokenProvider(
ISettingProvider settingProvider,
IHttpClientFactory httpClientFactory,
IMemoryCache memoryCache,
IDistributedCache<WeChatWorkTokenCacheItem> cache,
IOptionsMonitor<WeChatWorkOptions> weChatWorkOptions)
{
public ILogger<WeChatWorkTokenProvider> Logger { get; set; }
protected ISettingProvider SettingProvider { get; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IDistributedCache<WeChatWorkTokenCacheItem> Cache { get; }
protected WeChatWorkOptions WeChatWorkOptions { get; }
public WeChatWorkTokenProvider(
ISettingProvider settingProvider,
IHttpClientFactory httpClientFactory,
IDistributedCache<WeChatWorkTokenCacheItem> cache,
IOptionsMonitor<WeChatWorkOptions> weChatWorkOptions)
{
HttpClientFactory = httpClientFactory;
SettingProvider = settingProvider;
Cache = cache;
WeChatWorkOptions = weChatWorkOptions.CurrentValue;
HttpClientFactory = httpClientFactory;
SettingProvider = settingProvider;
MemoryCache = memoryCache;
WeChatWorkTokenCache = cache;
WeChatWorkOptions = weChatWorkOptions.CurrentValue;
Logger = NullLogger<WeChatWorkTokenProvider>.Instance;
}
Logger = NullLogger<WeChatWorkTokenProvider>.Instance;
}
public async virtual Task<WeChatWorkToken> GetTokenAsync(string agentId, CancellationToken cancellationToken = default)
{
var corpId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.CorpId);
public async virtual Task<WeChatWorkToken> GetTokenAsync(string agentId, CancellationToken cancellationToken = default)
{
var corpId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.CorpId);
return await GetTokenAsync(corpId, agentId, cancellationToken);
}
return await GetTokenAsync(corpId, agentId, cancellationToken);
}
public async virtual Task<WeChatWorkToken> GetTokenAsync(
string corpId,
string agentId,
CancellationToken cancellationToken = default)
public async virtual Task<WeChatWorkToken> GetTokenAsync(
string corpId,
string agentId,
CancellationToken cancellationToken = default)
{
return (await GetCacheItemAsync("WeChatWorkToken", corpId, agentId, cancellationToken)).Token;
}
/// <summary>
/// 获取缓存中的Token配置
/// </summary>
/// <param name="provider"></param>
/// <param name="corpId"></param>
/// <param name="agentId"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected async virtual Task<WeChatWorkTokenCacheItem> GetCacheItemAsync(
string provider,
string corpId,
string agentId,
CancellationToken cancellationToken = default)
{
Check.NotNullOrEmpty(corpId, nameof(corpId));
Check.NotNullOrEmpty(agentId, nameof(agentId));
var cacheKey = WeChatWorkTokenCacheItem.CalculateCacheKey(provider, corpId, agentId);
return await GetOrRefreshMemoryCacheAsync(cacheKey, provider, corpId, agentId);
}
/// <summary>
/// 获取或刷新内存缓存中的Token配置
/// </summary>
/// <param name="cacheKey"></param>
/// <param name="provider"></param>
/// <param name="corpId"></param>
/// <param name="agentId"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected async virtual Task<WeChatWorkTokenCacheItem> GetOrRefreshMemoryCacheAsync(
string cacheKey,
string provider,
string corpId,
string agentId,
CancellationToken cancellationToken = default)
{
if (MemoryCache.TryGetValue<WeChatWorkTokenCacheItem>(cacheKey, out var cacheItem))
{
return (await GetCacheItemAsync("WeChatWorkToken", corpId, agentId, cancellationToken)).Token;
return cacheItem;
}
protected async virtual Task<WeChatWorkTokenCacheItem> GetCacheItemAsync(
string provider,
string corpId,
string agentId,
CancellationToken cancellationToken = default)
cacheItem = await GetOrRefreshDistributedCacheAsync(cacheKey, provider, corpId, agentId);
var cacheOptions = new MemoryCacheEntryOptions
{
Check.NotNullOrEmpty(corpId, nameof(corpId));
Check.NotNullOrEmpty(agentId, nameof(agentId));
var cacheKey = WeChatWorkTokenCacheItem.CalculateCacheKey(provider, corpId, agentId);
Logger.LogDebug($"WeChatWorkTokenProvider.GetCacheItemAsync: {cacheKey}");
var cacheItem = await Cache.GetAsync(cacheKey, token: cancellationToken);
if (cacheItem != null)
AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(cacheItem.Token.ExpiresIn - 120),
};
cacheOptions.RegisterPostEvictionCallback(async (key, value, reason, state) =>
{
if (reason == EvictionReason.Expired)
{
Logger.LogDebug($"Found WeChatWorkToken in the cache: {cacheKey}");
return cacheItem;
await GetOrRefreshDistributedCacheAsync(cacheKey, provider, corpId, agentId);
}
});
return MemoryCache.Set(cacheKey, cacheItem, cacheOptions);
}
/// <summary>
/// 获取或刷新分布式缓存中的Token配置
/// </summary>
/// <param name="cacheKey"></param>
/// <param name="provider"></param>
/// <param name="corpId"></param>
/// <param name="agentId"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected async virtual Task<WeChatWorkTokenCacheItem> GetOrRefreshDistributedCacheAsync(
string cacheKey,
string provider,
string corpId,
string agentId,
CancellationToken cancellationToken = default)
{
var cacheItem = await WeChatWorkTokenCache.GetAsync(cacheKey, token: cancellationToken);
if (cacheItem != null)
{
Logger.LogDebug($"Found WeChatWorkToken in the cache: {cacheKey}");
return cacheItem;
}
Logger.LogDebug($"Not found WeChatWorkToken in the cache, getting from the httpClient: {cacheKey}");
Logger.LogDebug($"Not found WeChatWorkToken in the cache, getting from the httpClient: {cacheKey}");
var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient);
var applicationConfiguration = WeChatWorkOptions.Applications.GetConfiguration(agentId);
var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient);
var applicationConfiguration = WeChatWorkOptions.Applications.GetConfiguration(agentId);
var request = new WeChatWorkTokenRequest
{
CorpId = corpId,
CorpSecret = applicationConfiguration.Secret,
};
var request = new WeChatWorkTokenRequest
{
CorpId = corpId,
CorpSecret = applicationConfiguration.Secret,
};
using var response = await client.GetTokenAsync(request, cancellationToken);
var responseContent = await response.Content.ReadAsStringAsync();
// 改为直接引用 Newtownsoft.Json
var tokenResponse = JsonConvert.DeserializeObject<WeChatWorkTokenResponse>(responseContent);
var token = tokenResponse.ToWeChatWorkToken();
cacheItem = new WeChatWorkTokenCacheItem(corpId, agentId, token);
using var response = await client.GetTokenAsync(request, cancellationToken);
var tokenResponse = await response.DeserializeObjectAsync<WeChatWorkTokenResponse>();
var token = tokenResponse.ToWeChatWorkToken();
cacheItem = new WeChatWorkTokenCacheItem(corpId, agentId, token);
Logger.LogDebug($"Setting the cache item: {cacheKey}");
Logger.LogDebug($"Setting the cache item: {cacheKey}");
var cacheOptions = new DistributedCacheEntryOptions
{
// 设置绝对过期时间为Token有效期剩余的二分钟
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(token.ExpiresIn - 120),
};
var cacheOptions = new DistributedCacheEntryOptions
{
// 设置绝对过期时间为Token有效期剩余的二分钟
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(token.ExpiresIn - 100),
};
await Cache.SetAsync(cacheKey, cacheItem, cacheOptions, token: cancellationToken);
await WeChatWorkTokenCache.SetAsync(cacheKey, cacheItem, cacheOptions, token: cancellationToken);
Logger.LogDebug($"Finished setting the cache item: {cacheKey}");
Logger.LogDebug($"Finished setting the cache item: {cacheKey}");
return cacheItem;
}
return cacheItem;
}
}

12
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkRequest.cs

@ -0,0 +1,12 @@
using System;
namespace LINGYUN.Abp.WeChat.Work;
[Serializable]
public abstract class WeChatWorkRequest
{
public virtual string SerializeToJson()
{
return WeChatObjectSerializeExtensions.SerializeToJson(this);
}
}

2
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/WeChatWorkResponse.cs

@ -1,10 +1,12 @@
using Newtonsoft.Json;
using System;
using System.Text.Json.Serialization;
namespace LINGYUN.Abp.WeChat.Work;
/// <summary>
/// 企业微信请求响应
/// </summary>
[Serializable]
public class WeChatWorkResponse
{
/// <summary>

46
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Auth.cs

@ -0,0 +1,46 @@
using LINGYUN.Abp.WeChat.Work.Authorize.Request;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
{
internal static partial class HttpClientWeChatWorkRequestExtensions
{
public async static Task<HttpResponseMessage> GetUserInfoAsync(
this HttpMessageInvoker client,
string accessToken,
string code,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/auth/getuserinfo");
urlBuilder.AppendFormat("?access_token={0}", accessToken);
urlBuilder.AppendFormat("&code={0}", code);
var httpRequest = new HttpRequestMessage(HttpMethod.Get, urlBuilder.ToString());
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> GetUserDetailAsync(
this HttpMessageInvoker client,
string accessToken,
WeChatWorkUserDetailRequest request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/auth/getuserdetail");
urlBuilder.AppendFormat("?access_token={0}", accessToken);
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = new StringContent(request.SerializeToJson())
};
return await client.SendAsync(httpRequest, cancellationToken);
}
}
}

68
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Chat.cs

@ -0,0 +1,68 @@
using LINGYUN.Abp.WeChat.Work.Chat.Request;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
{
internal static partial class HttpClientWeChatWorkRequestExtensions
{
public async static Task<HttpResponseMessage> GetAppChatAsync(
this HttpMessageInvoker client,
string accessToken,
string chatId,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/appchat/get");
urlBuilder.AppendFormat("?access_token={0}", accessToken);
urlBuilder.AppendFormat("&chatid={0}", chatId);
var httpRequest = new HttpRequestMessage(
HttpMethod.Get,
urlBuilder.ToString());
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> CreateAppChatAsync(
this HttpMessageInvoker client,
string accessToken,
WeChatWorkAppChatCreateRequest request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/appchat/create");
urlBuilder.AppendFormat("?access_token={0}", accessToken);
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = new StringContent(request.SerializeToJson())
};
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> UpdateAppChatAsync(
this HttpMessageInvoker client,
string accessToken,
WeChatWorkAppChatUpdateRequest request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/appchat/update");
urlBuilder.AppendFormat("?access_token={0}", accessToken);
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = new StringContent(request.SerializeToJson())
};
return await client.SendAsync(httpRequest, cancellationToken);
}
}
}

70
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Media.cs

@ -0,0 +1,70 @@
using LINGYUN.Abp.WeChat.Work.Media.Models;
using LINGYUN.Abp.WeChat.Work.Utils;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
{
internal static partial class HttpClientWeChatWorkRequestExtensions
{
public async static Task<HttpResponseMessage> GetMediaAsync(
this HttpMessageInvoker client,
string accessToken,
string mediaId,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/media/get");
urlBuilder.AppendFormat("?access_token={0}", accessToken);
urlBuilder.AppendFormat("&media_id={0}", mediaId);
var httpRequest = new HttpRequestMessage(HttpMethod.Get, urlBuilder.ToString());
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> UploadMediaAsync(
this HttpMessageInvoker client,
string type,
WeChatWorkMediaRequest request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/media/upload");
urlBuilder.AppendFormat("?access_token={0}", request.AccessToken);
urlBuilder.AppendFormat("&type={0}", type);
var fileBytes = await request.Content.GetStream().GetAllBytesAsync();
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = HttpContentBuildHelper.BuildUploadMediaContent("media", fileBytes, request.Content.FileName)
};
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> UploadImageAsync(
this HttpMessageInvoker client,
WeChatWorkMediaRequest request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/media/uploadimg");
urlBuilder.AppendFormat("?access_token={0}", request.AccessToken);
var fileBytes = await request.Content.GetStream().GetAllBytesAsync();
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = HttpContentBuildHelper.BuildUploadMediaContent("file", fileBytes, request.Content.FileName)
};
return await client.SendAsync(httpRequest, cancellationToken);
}
}
}

68
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Message.cs

@ -0,0 +1,68 @@
using LINGYUN.Abp.WeChat.Work.Message;
using LINGYUN.Abp.WeChat.Work.Message.Request;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
{
internal static partial class HttpClientWeChatWorkRequestExtensions
{
public async static Task<HttpResponseMessage> SendMessageAsync(
this HttpMessageInvoker client,
WeChatWorkMessageRequest<WeChatWorkMessage> request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/message/send");
urlBuilder.AppendFormat("?access_token={0}", request.AccessToken);
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = new StringContent(request.Message.SerializeToJson())
};
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> SendMessageAsync(
this HttpMessageInvoker client,
WeChatWorkMessageRequest<WeChatWorkAppChatMessage> request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/appchat/send");
urlBuilder.AppendFormat("?access_token={0}", request.AccessToken);
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = new StringContent(request.Message.SerializeToJson())
};
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> ReCallMessageAsync(
this HttpMessageInvoker client,
WeChatWorkMessageReCallRequest request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/message/recall");
urlBuilder.AppendFormat("?access_token={0}", request.AccessToken);
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = new StringContent(request.SerializeToJson())
};
return await client.SendAsync(httpRequest, cancellationToken);
}
}
}

123
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.cs

@ -1,17 +1,11 @@
using LINGYUN.Abp.WeChat.Work.Authorize.Request;
using LINGYUN.Abp.WeChat.Work.Media;
using LINGYUN.Abp.WeChat.Work.Message;
using LINGYUN.Abp.WeChat.Work.Token;
using LINGYUN.Abp.WeChat.Work.Utils;
using Newtonsoft.Json;
using System.IO;
using LINGYUN.Abp.WeChat.Work.Token.Models;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
{
internal static class HttpClientWeChatWorkRequestExtensions
internal static partial class HttpClientWeChatWorkRequestExtensions
{
public async static Task<HttpResponseMessage> GetTokenAsync(this HttpMessageInvoker client, WeChatWorkTokenRequest request, CancellationToken cancellationToken = default)
{
@ -24,118 +18,5 @@ namespace System.Net.Http
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> GetMediaAsync(
this HttpMessageInvoker client,
string accessToken,
string mediaId,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/media/get");
urlBuilder.AppendFormat("?access_token={0}", accessToken);
urlBuilder.AppendFormat("&media_id={0}", mediaId);
var httpRequest = new HttpRequestMessage(HttpMethod.Get, urlBuilder.ToString());
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> GetUserInfoAsync(
this HttpMessageInvoker client,
string accessToken,
string code,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/auth/getuserinfo");
urlBuilder.AppendFormat("?access_token={0}", accessToken);
urlBuilder.AppendFormat("&code={0}", code);
var httpRequest = new HttpRequestMessage(HttpMethod.Get, urlBuilder.ToString());
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> GetUserDetailAsync(
this HttpMessageInvoker client,
string accessToken,
WeChatWorkUserDetailRequest request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/auth/getuserdetail");
urlBuilder.AppendFormat("?access_token={0}", accessToken);
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = new StringContent(request.SerializeToJson())
};
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> UploadMediaAsync(
this HttpMessageInvoker client,
string type,
WeChatWorkMediaRequest request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/media/upload");
urlBuilder.AppendFormat("?access_token={0}", request.AccessToken);
urlBuilder.AppendFormat("&type={0}", type);
var fileBytes = await request.Content.GetStream().GetAllBytesAsync();
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = HttpContentBuildHelper.BuildUploadMediaContent("media", fileBytes, request.Content.FileName)
};
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> UploadImageAsync(
this HttpMessageInvoker client,
WeChatWorkMediaRequest request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/media/uploadimg");
urlBuilder.AppendFormat("?access_token={0}", request.AccessToken);
var fileBytes = await request.Content.GetStream().GetAllBytesAsync();
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = HttpContentBuildHelper.BuildUploadMediaContent("file", fileBytes, request.Content.FileName)
};
return await client.SendAsync(httpRequest, cancellationToken);
}
public async static Task<HttpResponseMessage> SendMessageAsync(
this HttpMessageInvoker client,
WeChatWorkMessageRequest request,
CancellationToken cancellationToken = default)
{
var urlBuilder = new StringBuilder();
urlBuilder.Append("/cgi-bin/message/send");
urlBuilder.AppendFormat("?access_token={0}", request.AccessToken);
var httpRequest = new HttpRequestMessage(
HttpMethod.Post,
urlBuilder.ToString())
{
Content = new StringContent(request.Message.SerializeToJson())
};
return await client.SendAsync(httpRequest, cancellationToken);
}
}
}

18
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpResponseDeserializeExtensions.cs

@ -0,0 +1,18 @@
using LINGYUN.Abp.WeChat.Work;
using System.Threading.Tasks;
using Volo.Abp.Http.Client;
namespace System.Net.Http;
internal static class HttpResponseDeserializeExtensions
{
public async static Task<T> DeserializeObjectAsync<T>(this HttpResponseMessage response) where T : WeChatWorkResponse
{
if (!response.IsSuccessStatusCode)
{
throw new AbpRemoteCallException($"Wechat work request error: {response.StatusCode} - {response.ReasonPhrase}");
}
var responseContent = await response.Content.ReadAsStringAsync();
return responseContent.DeserializeObject<T>();
}
}

10
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/WeChatObjectSerializeExtensions.cs

@ -0,0 +1,10 @@
using Newtonsoft.Json;
namespace System;
internal static class WeChatObjectSerializeExtensions
{
public static string SerializeToJson(this object @object)
{
return JsonConvert.SerializeObject(@object);
}
}

11
aspnet-core/modules/wechat/LINGYUN.Abp.WeChat.Work/System/WeChatWorkResponseDeserializeExtensions.cs

@ -0,0 +1,11 @@
using LINGYUN.Abp.WeChat.Work;
using Newtonsoft.Json;
namespace System;
internal static class WeChatWorkResponseDeserializeExtensions
{
public static T DeserializeObject<T>(this string responseContent) where T : WeChatWorkResponse
{
return JsonConvert.DeserializeObject<T>(responseContent);
}
}

6
aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/LY.MicroService.BackendAdmin.HttpApi.Host.csproj

@ -86,4 +86,10 @@
<ProjectReference Include="..\..\modules\text-templating\LINGYUN.Abp.TextTemplating.HttpApi\LINGYUN.Abp.TextTemplating.HttpApi.csproj" />
<ProjectReference Include="..\..\modules\text-templating\LINGYUN.Abp.TextTemplating.Scriban\LINGYUN.Abp.TextTemplating.Scriban.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.secrets.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

20
aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/appsettings.Development.json

@ -30,15 +30,15 @@
}
},
"ConnectionStrings": {
"Default": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456",
"AbpIdentity": "Server=127.0.0.1;Database=IdentityServer-v70;User Id=root;Password=123456",
"AbpIdentityServer": "Server=127.0.0.1;Database=IdentityServer-v70;User Id=root;Password=123456",
"AbpSaas": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456",
"AbpSettingManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456",
"AbpFeatureManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456",
"AbpPermissionManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456",
"AbpLocalizationManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456",
"AbpTextTemplating": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456"
"Default": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456;SslMode=None",
"AbpIdentity": "Server=127.0.0.1;Database=IdentityServer-v70;User Id=root;Password=123456;SslMode=None",
"AbpIdentityServer": "Server=127.0.0.1;Database=IdentityServer-v70;User Id=root;Password=123456;SslMode=None",
"AbpSaas": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456;SslMode=None",
"AbpSettingManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456;SslMode=None",
"AbpFeatureManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456;SslMode=None",
"AbpPermissionManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456;SslMode=None",
"AbpLocalizationManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456;SslMode=None",
"AbpTextTemplating": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456;SslMode=None"
},
"CAP": {
"EventBus": {
@ -50,7 +50,7 @@
},
"MySql": {
"TableNamePrefix": "admin",
"ConnectionString": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456"
"ConnectionString": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456;SslMode=None"
},
"RabbitMQ": {
"HostName": "127.0.0.1",

3
aspnet-core/tests/LINGYUN.Abp.WeChat.Work.Tests/GlobalUsings.cs

@ -1 +1,2 @@
global using Xunit;
global using Xunit;
global using Shouldly;

20
aspnet-core/tests/LINGYUN.Abp.WeChat.Work.Tests/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkTestModule.cs

@ -1,5 +1,6 @@
using Castle.Core.Configuration;
using LINGYUN.Abp.Tests;
using LINGYUN.Abp.Tests;
using LINGYUN.Abp.Tests.Features;
using LINGYUN.Abp.WeChat.Work.Features;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@ -41,5 +42,20 @@ public class AbpWeChatWorkTestModule : AbpModule
options.ConfigurationOptions = redisConfig;
options.InstanceName = configuration["Redis:InstanceName"];
});
Configure<FakeFeatureOptions>(options =>
{
options.Map(WeChatWorkFeatureNames.Enable, (feature) =>
{
return true.ToString();
});
options.Map(WeChatWorkFeatureNames.Message.Enable, (feature) =>
{
return true.ToString();
});
options.Map(WeChatWorkFeatureNames.AppChat.Message.Enable, (feature) =>
{
return true.ToString();
});
});
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save