Browse Source

feat: added support webhook management ui.

pull/543/head
cKey 4 years ago
parent
commit
0b08158ef3
  1. 1
      .gitignore
  2. 44
      apps/vue/.env.production
  3. 30
      apps/vue/src/api/webhooks/model/sendAttemptsModel.ts
  4. 46
      apps/vue/src/api/webhooks/model/subscriptionsModel.ts
  5. 48
      apps/vue/src/api/webhooks/send-attempts.ts
  6. 72
      apps/vue/src/api/webhooks/subscriptions.ts
  7. 50
      apps/vue/src/enums/httpEnum.ts
  8. 163
      apps/vue/src/views/webhooks/send-attempts/components/SendAttemptModal.vue
  9. 97
      apps/vue/src/views/webhooks/send-attempts/components/SendAttemptTable.vue
  10. 84
      apps/vue/src/views/webhooks/send-attempts/datas/ModalData.ts
  11. 52
      apps/vue/src/views/webhooks/send-attempts/datas/TableData.ts
  12. 16
      apps/vue/src/views/webhooks/send-attempts/index.vue
  13. 179
      apps/vue/src/views/webhooks/subscriptions/components/SubscriptionModal.vue
  14. 103
      apps/vue/src/views/webhooks/subscriptions/components/SubscriptionTable.vue
  15. 108
      apps/vue/src/views/webhooks/subscriptions/datas/ModalData.ts
  16. 66
      apps/vue/src/views/webhooks/subscriptions/datas/TableData.ts
  17. 16
      apps/vue/src/views/webhooks/subscriptions/index.vue
  18. 76
      apps/vue/src/views/webhooks/typing.ts
  19. 32
      aspnet-core/modules/platform/LINGYUN.Abp.UI.Navigation.VueVbenAdmin/LINGYUN/Abp/UI/Navigation/VueVbenAdmin/AbpUINavigationVueVbenAdminNavigationDefinitionProvider.cs
  20. 24
      aspnet-core/modules/platform/LINGYUN.Abp.UI.Navigation.VueVbenAdmin/LINGYUN/Abp/UI/Navigation/VueVbenAdmin/VueVbenAdminNavigationSeedContributor.cs
  21. 40
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/ConnectionStringInvalidator.cs
  22. 1
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/NullJobPublisher.cs
  23. 1
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/NullJobScheduler.cs
  24. 7
      aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateDto.cs
  25. 2
      aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobInfoAppService.cs
  26. 19
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Application.Contracts/LINGYUN/Abp/WebhooksManagement/Authorization/WebhooksManagementPermissionDefinitionProvider.cs
  27. 1
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Application.Contracts/LINGYUN/Abp/WebhooksManagement/Authorization/WebhooksManagementPermissions.cs
  28. 2
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Application.Contracts/LINGYUN/Abp/WebhooksManagement/IWebhookSendRecordAppService.cs
  29. 2
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Application.Contracts/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordGetListInput.cs
  30. 9
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Application/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordAppService.cs
  31. 34
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/Localization/Resources/en.json
  32. 34
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/Localization/Resources/zh-Hans.json
  33. 3
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookEventRecord.cs
  34. 3
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSendRecord.cs
  35. 2
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordFilter.cs
  36. 1
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/EfCoreWebhookSendRecordRepository.cs
  37. 14
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.HttpApi/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordController.cs
  38. 12
      aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.HttpApi/LINGYUN/Abp/WebhooksManagement/WebhookSubscriptionController.cs
  39. 2
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/Properties/launchSettings.json
  40. 4
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/Ocelot/Configuration/Repository/DiskFileConfigurationAggragatorRepository.cs
  41. 60
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.Development.json
  42. 13
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.aggregate.json
  43. 59
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.webhook.json

1
.gitignore

@ -2,7 +2,6 @@
node_modules node_modules
/dist /dist
vue.config.js vue.config.js
.env.production
task task
obj obj
bin bin

44
apps/vue/.env.production

@ -0,0 +1,44 @@
# Whether to open mock
VITE_USE_MOCK=false
# public path
VITE_PUBLIC_PATH=/
# Delete console
VITE_DROP_CONSOLE=true
# Whether to enable gzip or brotli compression
# Optional: gzip | brotli | none
# If you need multiple forms, you can use `,` to separate
VITE_BUILD_COMPRESS='none'
# Whether to delete origin files when using compress, default false
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE=false
# Basic interface address SPA
VITE_GLOB_API_URL=/api
# File upload address, optional
# It can be forwarded by nginx or write the actual address directly
VITE_GLOB_UPLOAD_URL=/upload
# Interface prefix
VITE_GLOB_API_URL_PREFIX=
# Whether to enable image compression
VITE_USE_IMAGEMIN=true
# use pwa
VITE_USE_PWA=false
# Is it compatible with older browsers
VITE_LEGACY=false
# Multi-tenancy key
VITE_GLOB_MULTITENANCY_KEY='__tenant'
# STS Connect
VITE_GLOB_AUTHORITY='http://127.0.0.1:44385'
VITE_GLOB_CLIENT_ID='vue-admin-element'
VITE_GLOB_CLIENT_SECRET='1q2w3e*'

30
apps/vue/src/api/webhooks/model/sendAttemptsModel.ts

@ -0,0 +1,30 @@
import { PagedAndSortedResultRequestDto } from '../../model/baseModel';
import { HttpStatusCode } from '/@/enums/httpEnum';
export interface WebhookEvent {
tenantId?: string;
webhookName: string;
data: string;
creationTime: Date;
}
export interface WebhookSendAttempt {
id: string;
tenantId?: string;
webhookEventId: string;
webhookSubscriptionId: string;
response: string;
responseStatusCode?: HttpStatusCode;
creationTime: Date;
lastModificationTime?: Date;
webhookEvent: WebhookEvent;
}
export interface WebhookSendAttemptGetListInput extends PagedAndSortedResultRequestDto {
filter?: string;
webhookEventId?: string;
subscriptionId?: string;
responseStatusCode?: HttpStatusCode;
beginCreationTime?: Date;
endCreationTime?: Date;
}

46
apps/vue/src/api/webhooks/model/subscriptionsModel.ts

@ -0,0 +1,46 @@
import { CreationAuditedEntityDto, PagedAndSortedResultRequestDto } from '../../model/baseModel';
export interface WebhookSubscription extends CreationAuditedEntityDto {
id: string;
tenantId?: string;
webhookUri: string;
secret: string;
isActive: boolean;
webhooks: string[];
headers: { [key: string]: string };
}
export interface WebhookSubscriptionCreateOrUpdate {
webhookUri: string;
secret: string;
isActive: boolean;
webhooks: string[];
headers: { [key: string]: string };
}
export type CreateWebhookSubscription = WebhookSubscriptionCreateOrUpdate;
export type UpdateWebhookSubscription = WebhookSubscriptionCreateOrUpdate;
export interface WebhookAvailable {
name: string;
displayName: string;
description: string;
}
export interface WebhookAvailableGroup {
name: string;
displayName: string;
webhooks: WebhookAvailable[];
}
export interface WebhookSubscriptionGetListInput extends PagedAndSortedResultRequestDto {
filter?: string;
tenantId?: string;
webhookUri?: string;
secret?: string;
isActive?: boolean;
webhooks?: string;
beginCreationTime?: Date;
endCreationTime?: Date;
}

48
apps/vue/src/api/webhooks/send-attempts.ts

@ -0,0 +1,48 @@
import { defAbpHttp } from '/@/utils/http/abp';
import { PagedResultDto } from '../model/baseModel';
import { WebhookSendAttempt, WebhookSendAttemptGetListInput } from './model/sendAttemptsModel';
const remoteServiceName = 'WebhooksManagement';
const controllerName = 'WebhookSendRecord';
export const getById = (id: string) => {
return defAbpHttp.request<WebhookSendAttempt>({
service: remoteServiceName,
controller: controllerName,
action: 'GetAsync',
params: {
id: id,
},
});
};
export const deleteById = (id: string) => {
return defAbpHttp.request<WebhookSendAttempt>({
service: remoteServiceName,
controller: controllerName,
action: 'DeleteAsync',
params: {
id: id,
},
});
}
export const getList = (input: WebhookSendAttemptGetListInput) => {
return defAbpHttp.request<PagedResultDto<WebhookSendAttempt>>({
service: remoteServiceName,
controller: controllerName,
action: 'GetListAsync',
params: input,
});
};
export const resend = (id: string) => {
return defAbpHttp.request<void>({
service: remoteServiceName,
controller: controllerName,
action: 'ResendAsync',
params: {
id: id,
},
});
}

72
apps/vue/src/api/webhooks/subscriptions.ts

@ -0,0 +1,72 @@
import { defAbpHttp } from '/@/utils/http/abp';
import {
WebhookSubscription,
WebhookAvailableGroup,
CreateWebhookSubscription,
UpdateWebhookSubscription,
WebhookSubscriptionGetListInput,
} from './model/subscriptionsModel';
import { ListResultDto, PagedResultDto } from '../model/baseModel';
const remoteServiceName = 'WebhooksManagement';
const controllerName = 'WebhookSubscription';
export const create = (input: CreateWebhookSubscription) => {
return defAbpHttp.request<WebhookSubscription>({
service: remoteServiceName,
controller: controllerName,
action: 'CreateAsync',
data: input,
});
};
export const update = (id: string, input: UpdateWebhookSubscription) => {
return defAbpHttp.request<WebhookSubscription>({
service: remoteServiceName,
controller: controllerName,
action: 'UpdateAsync',
data: input,
params: {
id: id,
},
});
};
export const getById = (id: string) => {
return defAbpHttp.request<WebhookSubscription>({
service: remoteServiceName,
controller: controllerName,
action: 'GetAsync',
params: {
id: id,
},
});
};
export const deleteById = (id: string) => {
return defAbpHttp.request<WebhookSubscription>({
service: remoteServiceName,
controller: controllerName,
action: 'DeleteAsync',
params: {
id: id,
},
});
};
export const getList = (input: WebhookSubscriptionGetListInput) => {
return defAbpHttp.request<PagedResultDto<WebhookSubscription>>({
service: remoteServiceName,
controller: controllerName,
action: 'GetListAsync',
params: input,
});
};
export const getAllAvailableWebhooks = () => {
return defAbpHttp.request<ListResultDto<WebhookAvailableGroup>>({
service: remoteServiceName,
controller: controllerName,
action: 'GetAllAvailableWebhooksAsync',
});
};

50
apps/vue/src/enums/httpEnum.ts

@ -28,3 +28,53 @@ export enum ContentTypeEnum {
// form-data upload // form-data upload
FORM_DATA = 'multipart/form-data;charset=UTF-8', FORM_DATA = 'multipart/form-data;charset=UTF-8',
} }
export enum HttpStatusCode {
Continue = 100,
SwitchingProtocols = 101,
OK = 200,
Created = 201,
Accepted = 202,
NonAuthoritativeInformation = 203,
NoContent = 204,
ResetContent = 205,
PartialContent = 206,
Ambiguous = 300,
MultipleChoices = 300,
Moved = 301,
MovedPermanently = 301,
Found = 302,
Redirect = 302,
RedirectMethod = 303,
SeeOther = 303,
NotModified = 304,
UseProxy = 305,
Unused = 306,
RedirectKeepVerb = 307,
TemporaryRedirect = 307,
BadRequest = 400,
Unauthorized = 401,
PaymentRequired = 402,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
ProxyAuthenticationRequired = 407,
RequestTimeout = 408,
Conflict = 409,
Gone = 410,
LengthRequired = 411,
PreconditionFailed = 412,
RequestEntityTooLarge = 413,
RequestUriTooLong = 414,
UnsupportedMediaType = 415,
RequestedRangeNotSatisfiable = 416,
ExpectationFailed = 417,
UpgradeRequired = 426,
InternalServerError = 500,
NotImplemented = 501,
BadGateway = 502,
ServiceUnavailable = 503,
GatewayTimeout = 504,
HttpVersionNotSupported = 505,
}

163
apps/vue/src/views/webhooks/send-attempts/components/SendAttemptModal.vue

@ -0,0 +1,163 @@
<template>
<BasicModal
@register="registerModal"
:width="900"
:height="500"
:title="L('SendAttempts')"
:mask-closable="false"
>
<Form
ref="formElRef"
:colon="true"
label-align="left"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 18 }"
:model="modelRef"
>
<Tabs v-model:activeKey="activeKey">
<TabPane key="basic" :tab="L('BasicInfo')">
<FormItem :label="L('DisplayName:CreationTime')">
<Input readonly :value="getDateTime(modelRef.creationTime)" />
</FormItem>
<FormItem :label="L('DisplayName:ResponseStatusCode')">
<Tag v-if="modelRef.responseStatusCode" :color="getHttpStatusColor(modelRef.responseStatusCode)">{{ httpStatusCodeMap[modelRef.responseStatusCode] }}</Tag>
</FormItem>
<FormItem :label="L('DisplayName:Response')">
<CodeEditor readonly style="height: 300px;" :mode="MODE.HTML" v-model:value="modelRef.response" />
</FormItem>
</TabPane>
<TabPane v-if="modelRef.webhookEvent" key="event" :tab="L('WebhookEvent')">
<FormItem :label="L('DisplayName:WebhookEventId')">
<Input readonly :value="modelRef.webhookEventId" />
</FormItem>
<FormItem :label="L('DisplayName:WebhookName')">
<Input readonly :value="modelRef.webhookEvent.webhookName" />
</FormItem>
<FormItem :label="L('DisplayName:CreationTime')">
<Input readonly :value="getDateTime(modelRef.webhookEvent.creationTime)" />
</FormItem>
<FormItem :label="L('DisplayName:Data')">
<CodeEditor readonly style="height: 300px;" :mode="MODE.JSON" v-model:value="modelRef.webhookEvent.data" />
</FormItem>
</TabPane>
<TabPane v-if="subscriptionRef.id" key="subscription" :tab="L('Subscriptions')">
<FormItem :label="L('DisplayName:SubscriptionId')">
<Input readonly :value="modelRef.webhookSubscriptionId" />
</FormItem>
<FormItem :label="L('DisplayName:IsActive')">
<Checkbox disabled v-model:checked="subscriptionRef.isActive">{{ L('DisplayName:IsActive') }}</Checkbox>
</FormItem>
<FormItem :label="L('DisplayName:WebhookUri')">
<Input readonly :value="subscriptionRef.webhookUri" />
</FormItem>
<FormItem :label="L('DisplayName:Secret')">
<Input readonly :value="subscriptionRef.secret" />
</FormItem>
<FormItem :label="L('DisplayName:CreationTime')">
<Input readonly :value="getDateTime(subscriptionRef.creationTime)" />
</FormItem>
<FormItem :label="L('DisplayName:Webhooks')">
<TextArea readonly :value="getWebhooks(subscriptionRef.webhooks)" :auto-size="{ minRows: 5, maxRows: 10 }" />
</FormItem>
<FormItem name="headers" :label="L('DisplayName:Headers')">
<CodeEditor readonly style="height: 300px;" :mode="MODE.JSON" v-model:value="subscriptionRef.headers" />
</FormItem>
</TabPane>
</Tabs>
</Form>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import { useLocalization } from '/@/hooks/abp/useLocalization';
import {
Checkbox,
Form,
Tabs,
Tag,
Input,
} from 'ant-design-vue';
import { CodeEditor, MODE } from '/@/components/CodeEditor';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { getById } from '/@/api/webhooks/send-attempts';
import { getById as getSubscription } from '/@/api/webhooks/subscriptions';
import { WebhookSendAttempt } from '/@/api/webhooks/model/sendAttemptsModel';
import { WebhookSubscription } from '/@/api/webhooks/model/subscriptionsModel';
import { httpStatusCodeMap, getHttpStatusColor } from '../../typing';
import { formatToDateTime } from '/@/utils/dateUtil';
const FormItem = Form.Item;
const TabPane = Tabs.TabPane;
const TextArea = Input.TextArea;
const { L } = useLocalization('WebhooksManagement');
const formElRef = ref<any>();
const activeKey = ref('basic');
const modelRef = ref<WebhookSendAttempt>(getDefaultModel());
const subscriptionRef = ref<WebhookSubscription>(getDefaultSubscription());
const [registerModal] = useModalInner((model) => {
activeKey.value = 'basic';
fetchModel(model.id);
});
const getDateTime = computed(() => {
return (date?: Date) => {
return date ? formatToDateTime(date) : '';
}
});
const getWebhooks = computed(() => {
return (webhooks: string[]) => {
return webhooks.reduce((hook, p) => hook + p + '\n', '');
}
})
function fetchModel(id: string) {
if (!id) {
modelRef.value = getDefaultModel();
return;
}
getById(id).then((res) => {
modelRef.value = res;
fetchSubscription(res.webhookSubscriptionId);
});
}
function fetchSubscription(id: string) {
getSubscription(id).then((res) => {
subscriptionRef.value = res;
});
}
function getDefaultModel() : WebhookSendAttempt {
return {
id: '',
webhookEventId: '',
webhookSubscriptionId: '',
webhookEvent: {
tenantId: undefined,
webhookName: '',
data: '{}',
creationTime: new Date(),
},
response: '',
responseStatusCode: undefined,
creationTime: new Date(),
lastModificationTime: undefined,
}
}
function getDefaultSubscription() : WebhookSubscription {
return {
id: '',
webhooks: [],
webhookUri: '',
headers: {},
secret: '',
isActive: true,
creatorId: '',
creationTime: new Date(),
};
}
</script>

97
apps/vue/src/views/webhooks/send-attempts/components/SendAttemptTable.vue

@ -0,0 +1,97 @@
<template>
<div class="content">
<BasicTable @register="registerTable">
<template #code="{ record }">
<Tag :color="getHttpStatusColor(record.responseStatusCode)">{{ httpStatusCodeMap[record.responseStatusCode] }}</Tag>
</template>
<template #action="{ record }">
<TableAction
:stop-button-propagation="true"
:actions="[
{
auth: 'AbpWebhooks.SendAttempts',
label: L('Edit'),
icon: 'ant-design:edit-outlined',
onClick: handleEdit.bind(null, record),
},
{
auth: 'AbpWebhooks.SendAttempts.Delete',
color: 'error',
label: L('Delete'),
icon: 'ant-design:delete-outlined',
onClick: handleDelete.bind(null, record),
},
]"
:dropDownActions="[
{
auth: 'AbpWebhooks.SendAttempts.Resend',
label: L('Resend'),
ifShow: [JobStatus.Running, JobStatus.FailedRetry].includes(record.status),
onClick: handlePause.bind(null, record),
},
]"
/>
</template>
</BasicTable>
<SendAttemptModal @register="registerModal" />
</div>
</template>
<script lang="ts" setup>
import { Switch, Tag } from 'ant-design-vue';
import { useMessage } from '/@/hooks/web/useMessage';
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { useModal } from '/@/components/Modal';
import { BasicTable, TableAction, useTable } from '/@/components/Table';
import { formatPagedRequest } from '/@/utils/http/abp/helper';
import { getDataColumns } from '../datas/TableData';
import { getSearchFormSchemas } from '../datas/ModalData';
import { httpStatusCodeMap, getHttpStatusColor } from '../../typing';
import { getList } from '/@/api/webhooks/send-attempts';
import SendAttemptModal from './SendAttemptModal.vue';
const { createConfirm } = useMessage();
const { L } = useLocalization('WebhooksManagement');
const [registerModal, { openModal }] = useModal();
const [registerTable, { reload }] = useTable({
rowKey: 'id',
title: L('SendAttempts'),
columns: getDataColumns(),
api: getList,
beforeFetch: formatPagedRequest,
pagination: true,
striped: false,
useSearchForm: true,
showTableSetting: true,
bordered: true,
showIndexColumn: false,
canResize: false,
immediate: true,
clickToRowSelect: false,
formConfig: getSearchFormSchemas(),
actionColumn: {
width: 220,
title: L('Actions'),
dataIndex: 'action',
slots: { customRender: 'action' },
},
});
function handleEdit(record) {
openModal(true, record);
}
function handleDelete(record) {
createConfirm({
iconType: 'warning',
title: L('AreYouSure'),
content: L('ItemWillBeDeletedMessage'),
okCancel: true,
onOk: () => {
deleteById(record.id).then(() => {
reload();
});
},
});
}
</script>

84
apps/vue/src/views/webhooks/send-attempts/datas/ModalData.ts

@ -0,0 +1,84 @@
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { FormProps } from '/@/components/Form';
import { getList as getTenants } from '/@/api/saas/tenant';
import { getList as getSubscriptions } from '/@/api/webhooks/subscriptions';
import { httpStatusOptions } from '../../typing';
const { L } = useLocalization('WebhooksManagement', 'AbpUi');
export function getSearchFormSchemas(): Partial<FormProps> {
return {
labelWidth: 100,
schemas: [
{
field: 'tenantId',
component: 'ApiSelect',
label: L('DisplayName:TenantId'),
colProps: { span: 6 },
componentProps: {
api: getTenants,
params: {
skipCount: 0,
maxResultCount: 100,
},
resultField: 'items',
labelField: 'name',
valueField: 'id',
},
},
{
field: 'subscriptionId',
component: 'ApiSelect',
label: L('DisplayName:Subscription'),
colProps: { span: 12 },
componentProps: {
api: getSubscriptions,
params: {
skipCount: 0,
maxResultCount: 100,
},
resultField: 'items',
labelField: 'webhookUri',
valueField: 'id',
}
},
{
field: 'responseStatusCode',
component: 'Select',
label: L('DisplayName:ResponseStatusCode'),
colProps: { span: 6 },
componentProps: {
options: httpStatusOptions,
},
},
{
field: 'beginCreationTime',
component: 'DatePicker',
label: L('DisplayName:BeginCreationTime'),
colProps: { span: 6 },
componentProps: {
style: {
width: '100%',
},
},
},
{
field: 'endCreationTime',
component: 'DatePicker',
label: L('DisplayName:EndCreationTime'),
colProps: { span: 6 },
componentProps: {
style: {
width: '100%',
},
},
},
{
field: 'filter',
component: 'Input',
label: L('Search'),
colProps: { span: 12 },
},
],
};
}

52
apps/vue/src/views/webhooks/send-attempts/datas/TableData.ts

@ -0,0 +1,52 @@
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { BasicColumn } from '/@/components/Table';
import { formatToDateTime } from '/@/utils/dateUtil';
const { L } = useLocalization('WebhooksManagement');
export function getDataColumns(): BasicColumn[] {
return [
{
title: 'id',
dataIndex: 'id',
width: 1,
ifShow: false,
},
{
title: L('DisplayName:TenantId'),
dataIndex: 'tenantId',
align: 'left',
width: 150,
sorter: true,
fixed: 'left',
},
{
title: L('DisplayName:ResponseStatusCode'),
dataIndex: 'responseStatusCode',
align: 'left',
width: 180,
sorter: true,
slots: {
customRender: 'code',
}
},
{
title: L('DisplayName:CreationTime'),
dataIndex: 'creationTime',
align: 'left',
width: 150,
sorter: true,
format: (text) => {
return formatToDateTime(text);
},
},
{
title: L('DisplayName:Response'),
dataIndex: 'response',
align: 'left',
width: 'auto',
sorter: true,
},
];
}

16
apps/vue/src/views/webhooks/send-attempts/index.vue

@ -0,0 +1,16 @@
<template>
<SendAttemptTable />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import SendAttemptTable from './components/SendAttemptTable.vue';
export default defineComponent({
name: 'SendAttempts',
components: {
SendAttemptTable,
},
setup() {},
});
</script>

179
apps/vue/src/views/webhooks/subscriptions/components/SubscriptionModal.vue

@ -0,0 +1,179 @@
<template>
<BasicModal
@register="registerModal"
:width="800"
:height="400"
:title="modalTitle"
:mask-closable="false"
@ok="handleSubmit"
>
<Form
ref="formElRef"
label-align="left"
layout="horizontal"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 18 }"
:model="modelRef"
:rules="modelRules"
>
<FormItem name="tenantId" :label="L('DisplayName:TenantId')">
<Select v-model:value="modelRef.tenantId">
<SelectOption
v-for="tenant in tenantsRef"
:key="tenant.id"
:value="tenant.id"
>{{ tenant.name }}</SelectOption>
</Select>
</FormItem>
<FormItem name="isActive" :label="L('DisplayName:IsActive')">
<Checkbox v-model:checked="modelRef.isActive">{{ L('DisplayName:IsActive') }}</Checkbox>
</FormItem>
<FormItem name="webhookUri" required :label="L('DisplayName:WebhookUri')">
<Input v-model:value="modelRef.webhookUri" autocomplete="off" />
</FormItem>
<FormItem name="secret" required :label="L('DisplayName:Secret')">
<Input v-model:value="modelRef.secret" autocomplete="off" />
</FormItem>
<FormItem name="webhooks" :label="L('DisplayName:Webhooks')">
<Select v-model:value="modelRef.webhooks" mode="multiple">
<SelectGroup v-for="group in webhooksGroupRef" :key="group.name" :label="group.displayName">
<SelectOption
v-for="option in group.webhooks"
:key="option.name"
:value="option.name"
>{{ option.displayName }}</SelectOption>
</SelectGroup>
</Select>
</FormItem>
<FormItem name="headers" :label="L('DisplayName:Headers')">
<CodeEditor style="height: 300px;" :mode="MODE.JSON" v-model:value="modelRef.headers" />
</FormItem>
</Form>
</BasicModal>
</template>
<script lang="ts" setup>
import { computed, ref, reactive, unref, onMounted, nextTick } from 'vue';
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { useValidation } from '/@/hooks/abp/useValidation';
import { useMessage } from '/@/hooks/web/useMessage';
import {
Checkbox,
Form,
Select,
Input,
} from 'ant-design-vue';
import { CodeEditor, MODE } from '/@/components/CodeEditor';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { Tenant } from '/@/api/saas/model/tenantModel';
import { getList as getTenants } from '/@/api/saas/tenant';
import { getById, create, update, getAllAvailableWebhooks } from '/@/api/webhooks/subscriptions';
import { WebhookSubscription, WebhookAvailableGroup } from '/@/api/webhooks/model/subscriptionsModel';
const FormItem = Form.Item;
const SelectGroup = Select.OptGroup;
const SelectOption = Select.Option;
const emit = defineEmits(['change', 'register']);
const { L } = useLocalization('WebhooksManagement');
const { ruleCreator } = useValidation();
const { createMessage } = useMessage();
const formElRef = ref<any>();
const tenantsRef = ref<Tenant[]>([]);
const webhooksGroupRef = ref<WebhookAvailableGroup[]>([]);
const modelRef = ref<WebhookSubscription>(getDefaultModel());
const [registerModal, { closeModal, changeOkLoading }] = useModalInner((model) => {
fetchModel(model.id);
nextTick(() => {
const formEl = unref(formElRef);
formEl?.clearValidate();
});
});
const isEditModal = computed(() => {
if (modelRef.value.id) {
return true;
}
return false;
});
const modalTitle = computed(() => {
if (!isEditModal.value) {
return L('Subscriptions:AddNew');
}
return L('Subscriptions:Edit');
});
const modelRules = reactive({
webhookUri: ruleCreator.fieldRequired({
name: 'WebhookUri',
resourceName: 'WebhooksManagement',
prefix: 'DisplayName',
}),
secret: ruleCreator.fieldRequired({
name: 'Secret',
resourceName: 'WebhooksManagement',
prefix: 'DisplayName',
}),
});
onMounted(() => {
fetchTenants();
fetchAvailableWebhooks();
});
function fetchAvailableWebhooks() {
getAllAvailableWebhooks().then((res) => {
webhooksGroupRef.value = res.items;
});
}
function fetchTenants() {
getTenants({
skipCount: 0,
maxResultCount: 100,
sorting: undefined,
}).then((res) => {
tenantsRef.value = res.items;
})
}
function fetchModel(id: string) {
if (!id) {
modelRef.value = getDefaultModel();
return;
}
getById(id).then((res) => {
modelRef.value = res;
});
}
function handleSubmit() {
const formEl = unref(formElRef);
formEl?.validate().then(() => {
changeOkLoading(true);
const model = unref(modelRef);
const api = isEditModal.value
? update(model.id, Object.assign(model))
: create(Object.assign(model));
api.then(() => {
createMessage.success(L('Successful'));
formEl?.resetFields();
closeModal();
emit('change');
}).finally(() => {
changeOkLoading(false);
});
});
}
function getDefaultModel() : WebhookSubscription {
return {
id: '',
webhooks: [],
webhookUri: '',
headers: {},
secret: '',
isActive: true,
creatorId: '',
creationTime: new Date(),
};
}
</script>

103
apps/vue/src/views/webhooks/subscriptions/components/SubscriptionTable.vue

@ -0,0 +1,103 @@
<template>
<div class="content">
<BasicTable @register="registerTable">
<template #toolbar>
<a-button
v-auth="['AbpWebhooks.Subscriptions.Create']"
type="primary"
@click="handleAddNew"
>{{ L('Subscriptions:AddNew') }}</a-button
>
</template>
<template #active="{ record }">
<Switch :checked="record.isActive" disabled />
</template>
<template #webhooks="{ record }">
<Tag v-for="hook in record.webhooks" color="blue">{{ hook }}</Tag>
</template>
<template #action="{ record }">
<TableAction
:stop-button-propagation="true"
:actions="[
{
auth: 'AbpWebhooks.Subscriptions.Update',
label: L('Edit'),
icon: 'ant-design:edit-outlined',
onClick: handleEdit.bind(null, record),
},
{
auth: 'AbpWebhooks.Subscriptions.Delete',
color: 'error',
label: L('Delete'),
icon: 'ant-design:delete-outlined',
onClick: handleDelete.bind(null, record),
},
]"
/>
</template>
</BasicTable>
<SubscriptionModal @register="registerModal" @change="reload" />
</div>
</template>
<script lang="ts" setup>
import { Switch, Tag } from 'ant-design-vue';
import { useMessage } from '/@/hooks/web/useMessage';
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { useModal } from '/@/components/Modal';
import { BasicTable, TableAction, useTable } from '/@/components/Table';
import { formatPagedRequest } from '/@/utils/http/abp/helper';
import { getDataColumns } from '../datas/TableData';
import { getSearchFormSchemas } from '../datas/ModalData';
import { deleteById, getList } from '/@/api/webhooks/subscriptions';
import SubscriptionModal from './SubscriptionModal.vue';
const { createConfirm } = useMessage();
const { L } = useLocalization('WebhooksManagement');
const [registerModal, { openModal }] = useModal();
const [registerTable, { reload }] = useTable({
rowKey: 'id',
title: L('Subscriptions'),
columns: getDataColumns(),
api: getList,
beforeFetch: formatPagedRequest,
pagination: true,
striped: false,
useSearchForm: true,
showTableSetting: true,
bordered: true,
showIndexColumn: false,
canResize: false,
immediate: true,
clickToRowSelect: false,
formConfig: getSearchFormSchemas(),
actionColumn: {
width: 220,
title: L('Actions'),
dataIndex: 'action',
slots: { customRender: 'action' },
},
});
function handleAddNew() {
openModal(true, { id: null });
}
function handleEdit(record) {
openModal(true, record);
}
function handleDelete(record) {
createConfirm({
iconType: 'warning',
title: L('AreYouSure'),
content: L('ItemWillBeDeletedMessage'),
okCancel: true,
onOk: () => {
deleteById(record.id).then(() => {
reload();
});
},
});
}
</script>

108
apps/vue/src/views/webhooks/subscriptions/datas/ModalData.ts

@ -0,0 +1,108 @@
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { FormProps } from '/@/components/Form';
import { getList } from '/@/api/saas/tenant';
import { getAllAvailableWebhooks } from '/@/api/webhooks/subscriptions';
const { L } = useLocalization('WebhooksManagement', 'AbpUi');
function getAllAvailables(): Promise<any> {
return getAllAvailableWebhooks().then((res) => {
return res.items.map((group) => {
return {
label: group.displayName,
value: group.name,
options: group.webhooks.map((p) => {
return {
label: p.displayName,
value: p.name,
}
}),
}
})
});
}
export function getSearchFormSchemas(): Partial<FormProps> {
return {
labelWidth: 100,
schemas: [
{
field: 'tenantId',
component: 'ApiSelect',
label: L('DisplayName:TenantId'),
colProps: { span: 6 },
componentProps: {
api: getList,
params: {
skipCount: 0,
maxResultCount: 1000,
},
resultField: 'items',
labelField: 'name',
valueField: 'id',
},
},
{
field: 'webhookUri',
component: 'Input',
label: L('DisplayName:WebhookUri'),
colProps: { span: 12 },
},
{
field: 'secret',
component: 'Input',
label: L('DisplayName:Secret'),
colProps: { span: 6 },
},
{
field: 'isActive',
component: 'Checkbox',
label: L('DisplayName:IsActive'),
colProps: { span: 6 },
defaultValue: true,
renderComponentContent: L('DisplayName:IsActive'),
},
{
field: 'webhooks',
component: 'ApiSelect',
label: L('DisplayName:Webhooks'),
colProps: { span: 6 },
componentProps: {
api: () => getAllAvailables(),
showSearch: true,
filterOption: (onputValue: string, option: any) => {
return option.label.includes(onputValue);
},
},
},
{
field: 'beginCreationTime',
component: 'DatePicker',
label: L('DisplayName:BeginCreationTime'),
colProps: { span: 6 },
componentProps: {
style: {
width: '100%',
},
},
},
{
field: 'endCreationTime',
component: 'DatePicker',
label: L('DisplayName:EndCreationTime'),
colProps: { span: 6 },
componentProps: {
style: {
width: '100%',
},
},
},
{
field: 'filter',
component: 'Input',
label: L('Search'),
colProps: { span: 24 },
},
],
};
}

66
apps/vue/src/views/webhooks/subscriptions/datas/TableData.ts

@ -0,0 +1,66 @@
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { BasicColumn } from '/@/components/Table';
import { formatToDateTime } from '/@/utils/dateUtil';
const { L } = useLocalization('WebhooksManagement');
export function getDataColumns(): BasicColumn[] {
return [
{
title: 'id',
dataIndex: 'id',
width: 1,
ifShow: false,
},
{
title: L('DisplayName:TenantId'),
dataIndex: 'tenantId',
align: 'left',
width: 150,
sorter: true,
fixed: 'left',
},
{
title: L('DisplayName:WebhookUri'),
dataIndex: 'webhookUri',
align: 'left',
width: 300,
sorter: true,
fixed: 'left',
slots: {
customRender: 'name',
}
},
{
title: L('DisplayName:IsActive'),
dataIndex: 'isActive',
align: 'left',
width: 180,
sorter: true,
slots: {
customRender: 'active',
}
},
{
title: L('DisplayName:CreationTime'),
dataIndex: 'creationTime',
align: 'left',
width: 150,
sorter: true,
format: (text) => {
return formatToDateTime(text);
},
},
{
title: L('DisplayName:Webhooks'),
dataIndex: 'webhooks',
align: 'left',
width: 200,
sorter: true,
slots: {
customRender: 'webhooks',
},
},
];
}

16
apps/vue/src/views/webhooks/subscriptions/index.vue

@ -0,0 +1,16 @@
<template>
<SubscriptionTable />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import SubscriptionTable from './components/SubscriptionTable.vue';
export default defineComponent({
name: 'Subscriptions',
components: {
SubscriptionTable,
},
setup() {},
});
</script>

76
apps/vue/src/views/webhooks/typing.ts

@ -0,0 +1,76 @@
import { HttpStatusCode } from '/@/enums/httpEnum';
export const httpStatusCodeMap = {
[HttpStatusCode.Continue]: '100 - Continue',
[HttpStatusCode.SwitchingProtocols]: '101 - Switching Protocols',
[HttpStatusCode.OK]: '200 - OK',
[HttpStatusCode.Created]: '201 - Created',
[HttpStatusCode.Accepted]: '202 - Accepted',
[HttpStatusCode.NonAuthoritativeInformation]: '203 - Non Authoritative Information',
[HttpStatusCode.NoContent]: '204 - No Content',
[HttpStatusCode.ResetContent]: '205 - Reset Content',
[HttpStatusCode.PartialContent]: '206 - Partial Content',
[HttpStatusCode.Ambiguous]: '300 - Ambiguous',
[HttpStatusCode.MultipleChoices]: '300 - Multiple Choices',
[HttpStatusCode.Moved]: '301 - Moved',
[HttpStatusCode.MovedPermanently]: '301 - Moved Permanently',
[HttpStatusCode.Found]: '302 - Found',
[HttpStatusCode.Redirect]: '302 - Redirect',
[HttpStatusCode.RedirectMethod]: '303 - Redirect Method',
[HttpStatusCode.SeeOther]: '303 - See Other',
[HttpStatusCode.NotModified]: '304 - Not Modified',
[HttpStatusCode.UseProxy]: '305 - Use Proxy',
[HttpStatusCode.Unused]: '306 - Unused',
[HttpStatusCode.RedirectKeepVerb]: '307 - Redirect Keep Verb',
[HttpStatusCode.TemporaryRedirect]: '307 - Temporary Redirect',
[HttpStatusCode.BadRequest]: '400 - Bad Request',
[HttpStatusCode.Unauthorized]: '401 - Unauthorized',
[HttpStatusCode.PaymentRequired]: '402 - Payment Required',
[HttpStatusCode.Forbidden]: '403 - Forbidden',
[HttpStatusCode.NotFound]: '404 - Not Found',
[HttpStatusCode.MethodNotAllowed]: '405 - Method Not Allowed',
[HttpStatusCode.NotAcceptable]: '406 - Not Acceptable',
[HttpStatusCode.ProxyAuthenticationRequired]: '407 - Proxy Authentication Required',
[HttpStatusCode.RequestTimeout]: '408 - Request Timeout',
[HttpStatusCode.Conflict]: '409 - Conflict',
[HttpStatusCode.Gone]: '410 - Gone',
[HttpStatusCode.LengthRequired]: '411 - Length Required',
[HttpStatusCode.PreconditionFailed]: '412 - Precondition Failed',
[HttpStatusCode.RequestEntityTooLarge]: '413 - Request Entity Too Large',
[HttpStatusCode.RequestUriTooLong]: '414 - Request Uri Too Long',
[HttpStatusCode.UnsupportedMediaType]: '415 - Unsupported Media Type',
[HttpStatusCode.RequestedRangeNotSatisfiable]: '416 - Requested Range Not Satisfiable',
[HttpStatusCode.ExpectationFailed]: '417 - Expectation Failed',
[HttpStatusCode.UpgradeRequired]: '426 - Upgrade Required',
[HttpStatusCode.InternalServerError]: '500 - Internal Server Error',
[HttpStatusCode.NotImplemented]: '501 - Not Implemented',
[HttpStatusCode.BadGateway]: '502 - Bad Gateway',
[HttpStatusCode.ServiceUnavailable]: '503 - Service Unavailable',
[HttpStatusCode.GatewayTimeout]: '504 - Gateway Timeout',
[HttpStatusCode.HttpVersionNotSupported]: '505 - Http Version Not Supported',
}
export const httpStatusOptions = Object.keys(httpStatusCodeMap).map((key) => {
return {
label: httpStatusCodeMap[key],
value: key,
};
})
export function getHttpStatusColor(statusCode: HttpStatusCode) {
if (statusCode < 200) {
return 'default';
}
if (statusCode >= 200 && statusCode < 300) {
return 'success';
}
if (statusCode >= 300 && statusCode < 400) {
return 'processing';
}
if (statusCode >= 400 && statusCode < 500) {
return 'warning';
}
if (statusCode >= 500) {
return 'error';
}
}

32
aspnet-core/modules/platform/LINGYUN.Abp.UI.Navigation.VueVbenAdmin/LINGYUN/Abp/UI/Navigation/VueVbenAdmin/AbpUINavigationVueVbenAdminNavigationDefinitionProvider.cs

@ -16,6 +16,7 @@ namespace LINGYUN.Abp.UI.Navigation.VueVbenAdmin
context.Add(GetLocalization()); context.Add(GetLocalization());
context.Add(GetOssManagement()); context.Add(GetOssManagement());
context.Add(GetTaskManagement()); context.Add(GetTaskManagement());
context.Add(GetWebhooksManagement());
} }
private static NavigationDefinition GetDashboard() private static NavigationDefinition GetDashboard()
@ -394,9 +395,38 @@ namespace LINGYUN.Abp.UI.Navigation.VueVbenAdmin
displayName: "任务详情", displayName: "任务详情",
url: "/task-management/background-jobs/:id", url: "/task-management/background-jobs/:id",
component: "/task-management/background-jobs/components/BackgroundJobInfoDetail", component: "/task-management/background-jobs/components/BackgroundJobInfoDetail",
description: "任务详情")); description: "任务详情")
.SetProperty("hideMenu", "true")
.SetProperty("hideTab", "true"));
return new NavigationDefinition(task); return new NavigationDefinition(task);
} }
private static NavigationDefinition GetWebhooksManagement()
{
var webhooks = new ApplicationMenu(
name: "WebHooks",
displayName: "WebHooks",
url: "/webhooks",
component: "",
description: "WebHooks",
icon: "ic:outline-webhook");
webhooks.AddItem(
new ApplicationMenu(
name: "Subscriptions",
displayName: "管理订阅",
url: "/webhooks/subscriptions",
component: "/webhooks/subscriptions/index",
description: "管理订阅"));
webhooks.AddItem(
new ApplicationMenu(
name: "SendAttempts",
displayName: "管理记录",
url: "/webhooks/send-attempts",
component: "/webhooks/send-attempts/index",
description: "管理记录"));
return new NavigationDefinition(webhooks);
}
} }
} }

24
aspnet-core/modules/platform/LINGYUN.Abp.UI.Navigation.VueVbenAdmin/LINGYUN/Abp/UI/Navigation/VueVbenAdmin/VueVbenAdminNavigationSeedContributor.cs

@ -83,7 +83,17 @@ namespace LINGYUN.Abp.UI.Navigation.VueVbenAdmin
{ "hideTab", false }, { "hideTab", false },
{ "ignoreAuth", false }, { "ignoreAuth", false },
}; };
menuMeta.AddIfNotContains(menu.ExtraProperties); foreach (var prop in menu.ExtraProperties)
{
if (menuMeta.ContainsKey(prop.Key))
{
menuMeta[prop.Key] = prop.Value;
}
else
{
menuMeta.Add(prop.Key, prop.Value);
}
}
var seedMenu = await SeedMenuAsync( var seedMenu = await SeedMenuAsync(
layout: layout, layout: layout,
@ -126,7 +136,17 @@ namespace LINGYUN.Abp.UI.Navigation.VueVbenAdmin
{ "hideTab", false }, { "hideTab", false },
{ "ignoreAuth", false }, { "ignoreAuth", false },
}; };
menuMeta.AddIfNotContains(item.ExtraProperties); foreach (var prop in menu.ExtraProperties)
{
if (menuMeta.ContainsKey(prop.Key))
{
menuMeta[prop.Key] = prop.Value;
}
else
{
menuMeta.Add(prop.Key, prop.Value);
}
}
var seedMenu = await SeedMenuAsync( var seedMenu = await SeedMenuAsync(
layout: layout, layout: layout,

40
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/ConnectionStringInvalidator.cs

@ -0,0 +1,40 @@
using LINGYUN.Abp.MultiTenancy;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
namespace LINGYUN.Abp.Saas.Tenants;
public class ConnectionStringInvalidator :
IDistributedEventHandler<ConnectionStringCreatedEventData>,
IDistributedEventHandler<ConnectionStringDeletedEventData>,
ITransientDependency
{
protected IDistributedCache<TenantCacheItem> Cache { get; }
public ConnectionStringInvalidator(IDistributedCache<TenantCacheItem> cache)
{
Cache = cache;
}
public virtual async Task HandleEventAsync(ConnectionStringCreatedEventData eventData)
{
await Cache.RemoveAsync(
TenantCacheItem.CalculateCacheKey(
eventData.TenantId,
eventData.TenantName),
considerUow: true);
}
public virtual async Task HandleEventAsync(ConnectionStringDeletedEventData eventData)
{
await Cache.RemoveAsync(
TenantCacheItem.CalculateCacheKey(
eventData.TenantId,
eventData.TenantName),
considerUow: true);
}
}

1
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/NullJobPublisher.cs

@ -7,6 +7,7 @@ namespace LINGYUN.Abp.BackgroundTasks;
[Dependency(TryRegister = true)] [Dependency(TryRegister = true)]
public class NullJobPublisher : IJobPublisher, ISingletonDependency public class NullJobPublisher : IJobPublisher, ISingletonDependency
{ {
public static readonly NullJobPublisher Instance = new NullJobPublisher();
public Task<bool> PublishAsync(JobInfo job, CancellationToken cancellationToken = default) public Task<bool> PublishAsync(JobInfo job, CancellationToken cancellationToken = default)
{ {
return Task.FromResult(false); return Task.FromResult(false);

1
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/NullJobScheduler.cs

@ -8,6 +8,7 @@ namespace LINGYUN.Abp.BackgroundTasks;
[Dependency(TryRegister = true)] [Dependency(TryRegister = true)]
public class NullJobScheduler : IJobScheduler, ISingletonDependency public class NullJobScheduler : IJobScheduler, ISingletonDependency
{ {
public static readonly IJobScheduler Instance = new NullJobScheduler();
public Task<bool> ExistsAsync(JobInfo job, CancellationToken cancellationToken = default) public Task<bool> ExistsAsync(JobInfo job, CancellationToken cancellationToken = default)
{ {
return Task.FromResult(false); return Task.FromResult(false);

7
aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateDto.cs

@ -1,4 +1,5 @@
using System; using LINGYUN.Abp.BackgroundTasks;
using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Volo.Abp.Validation; using Volo.Abp.Validation;
@ -33,4 +34,8 @@ public class BackgroundJobInfoCreateDto : BackgroundJobInfoCreateOrUpdateDto
/// 结束时间 /// 结束时间
/// </summary> /// </summary>
public DateTime? EndTime { get; set; } public DateTime? EndTime { get; set; }
/// <summary>
/// 作业来源
/// </summary>
public JobSource Source { get; set; } = JobSource.User;
} }

2
aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobInfoAppService.cs

@ -44,7 +44,7 @@ public class BackgroundJobInfoAppService : TaskManagementApplicationService, IBa
input.BeginTime, input.BeginTime,
input.EndTime, input.EndTime,
input.Priority, input.Priority,
JobSource.User, input.Source,
input.MaxCount, input.MaxCount,
input.MaxTryCount, input.MaxTryCount,
CurrentTenant.Id); CurrentTenant.Id);

19
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Application.Contracts/LINGYUN/Abp/WebhooksManagement/Authorization/WebhooksManagementPermissionDefinitionProvider.cs

@ -17,28 +17,28 @@ public class WebhooksManagementPermissionDefinitionProvider : PermissionDefiniti
var subscription = group.AddPermission( var subscription = group.AddPermission(
WebhooksManagementPermissions.WebhookSubscription.Default, WebhooksManagementPermissions.WebhookSubscription.Default,
L("Permission:Subscriptions"), L("Permission:Subscriptions"),
MultiTenancySides.Host) MultiTenancySides.Host);
.WithProviders(ClientPermissionValueProvider.ProviderName);
subscription.AddChild( subscription.AddChild(
WebhooksManagementPermissions.WebhookSubscription.Create, WebhooksManagementPermissions.WebhookSubscription.Create,
L("Permission:Create"), L("Permission:Create"),
MultiTenancySides.Host) MultiTenancySides.Host);
.WithProviders(ClientPermissionValueProvider.ProviderName);
subscription.AddChild( subscription.AddChild(
WebhooksManagementPermissions.WebhookSubscription.Update, WebhooksManagementPermissions.WebhookSubscription.Update,
L("Permission:Update"), L("Permission:Update"),
MultiTenancySides.Host) MultiTenancySides.Host);
.WithProviders(ClientPermissionValueProvider.ProviderName);
subscription.AddChild( subscription.AddChild(
WebhooksManagementPermissions.WebhookSubscription.Delete, WebhooksManagementPermissions.WebhookSubscription.Delete,
L("Permission:Delete"), L("Permission:Delete"),
MultiTenancySides.Host) MultiTenancySides.Host);
.WithProviders(ClientPermissionValueProvider.ProviderName);
var sendAttempts = group.AddPermission( var sendAttempts = group.AddPermission(
WebhooksManagementPermissions.WebhooksSendAttempts.Default, WebhooksManagementPermissions.WebhooksSendAttempts.Default,
L("Permission:SendAttempts"), L("Permission:SendAttempts"),
MultiTenancySides.Host); MultiTenancySides.Host);
sendAttempts.AddChild(
WebhooksManagementPermissions.WebhooksSendAttempts.Delete,
L("Permission:Delete"),
MultiTenancySides.Host);
sendAttempts.AddChild( sendAttempts.AddChild(
WebhooksManagementPermissions.WebhooksSendAttempts.Resend, WebhooksManagementPermissions.WebhooksSendAttempts.Resend,
L("Permission:Resend"), L("Permission:Resend"),
@ -46,7 +46,8 @@ public class WebhooksManagementPermissionDefinitionProvider : PermissionDefiniti
group.AddPermission( group.AddPermission(
WebhooksManagementPermissions.Publish, WebhooksManagementPermissions.Publish,
L("Permission:Publish")) L("Permission:Publish"),
MultiTenancySides.Host)
.WithProviders(ClientPermissionValueProvider.ProviderName); .WithProviders(ClientPermissionValueProvider.ProviderName);
group.AddPermission( group.AddPermission(

1
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Application.Contracts/LINGYUN/Abp/WebhooksManagement/Authorization/WebhooksManagementPermissions.cs

@ -22,6 +22,7 @@ public static class WebhooksManagementPermissions
public static class WebhooksSendAttempts public static class WebhooksSendAttempts
{ {
public const string Default = GroupName + ".SendAttempts"; public const string Default = GroupName + ".SendAttempts";
public const string Delete = Default + ".Delete";
public const string Resend = Default + ".Resend"; public const string Resend = Default + ".Resend";
} }
} }

2
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Application.Contracts/LINGYUN/Abp/WebhooksManagement/IWebhookSendRecordAppService.cs

@ -9,6 +9,8 @@ public interface IWebhookSendRecordAppService : IApplicationService
{ {
Task<WebhookSendRecordDto> GetAsync(Guid id); Task<WebhookSendRecordDto> GetAsync(Guid id);
Task DeleteAsync(Guid id);
Task ResendAsync(Guid id); Task ResendAsync(Guid id);
Task<PagedResultDto<WebhookSendRecordDto>> GetListAsync(WebhookSendRecordGetListInput input); Task<PagedResultDto<WebhookSendRecordDto>> GetListAsync(WebhookSendRecordGetListInput input);

2
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Application.Contracts/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordGetListInput.cs

@ -8,6 +8,8 @@ public class WebhookSendRecordGetListInput : PagedAndSortedResultRequestDto
{ {
public string Filter { get; set; } public string Filter { get; set; }
public Guid? TenantId { get; set; }
public Guid? WebhookEventId { get; set; } public Guid? WebhookEventId { get; set; }
public Guid? SubscriptionId { get; set; } public Guid? SubscriptionId { get; set; }

9
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Application/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordAppService.cs

@ -33,10 +33,19 @@ public class WebhookSendRecordAppService : WebhooksManagementAppServiceBase, IWe
return ObjectMapper.Map<WebhookSendRecord, WebhookSendRecordDto>(sendRecord); return ObjectMapper.Map<WebhookSendRecord, WebhookSendRecordDto>(sendRecord);
} }
[Authorize(WebhooksManagementPermissions.WebhooksSendAttempts.Delete)]
public async virtual Task DeleteAsync(Guid id)
{
var sendRecord = await RecordRepository.GetAsync(id);
await RecordRepository.DeleteAsync(sendRecord);
}
public async virtual Task<PagedResultDto<WebhookSendRecordDto>> GetListAsync(WebhookSendRecordGetListInput input) public async virtual Task<PagedResultDto<WebhookSendRecordDto>> GetListAsync(WebhookSendRecordGetListInput input)
{ {
var filter = new WebhookSendRecordFilter var filter = new WebhookSendRecordFilter
{ {
TenantId = input.TenantId,
SubscriptionId = input.SubscriptionId, SubscriptionId = input.SubscriptionId,
ResponseStatusCode = input.ResponseStatusCode, ResponseStatusCode = input.ResponseStatusCode,
BeginCreationTime = input.BeginCreationTime, BeginCreationTime = input.BeginCreationTime,

34
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/Localization/Resources/en.json

@ -14,6 +14,38 @@
"Webhooks:010001": "Payload address {WebhookUri} has been mounted event {Webhooks}!", "Webhooks:010001": "Payload address {WebhookUri} has been mounted event {Webhooks}!",
"Webhooks:Tests": "Tests", "Webhooks:Tests": "Tests",
"Webhooks:CheckConnect": "Check Connect", "Webhooks:CheckConnect": "Check Connect",
"Webhooks:CheckConnectDesc": "When a third-party service is connected, it is used to check whether the communication is normal." "Webhooks:CheckConnectDesc": "When a third-party service is connected, it is used to check whether the communication is normal.",
"SendAttempts": "Send Attempts",
"BasicInfo": "Basic Info",
"Subscriptions": "Subscriptions",
"WebhookEvent": "Event",
"Subscriptions:AddNew": "Add New",
"Subscriptions:Edit": "Edit",
"Resend": "Resend",
"DisplayName:Name": "Name",
"DisplayName:DisplayName": "Display Name",
"DisplayName:Description": "Description",
"DisplayName:WebhookName": "Webhook Name",
"DisplayName:Subscription": "Subscription",
"DisplayName:Data": "Data",
"DisplayName:CreationTime": "Creation Time",
"DisplayName:WebhookEventId": "Event Id",
"DisplayName:WebhookSubscriptionId": "Subscription Id",
"DisplayName:Response": "Response",
"DisplayName:ResponseStatusCode": "Response Status Code",
"DisplayName:LastModificationTime": "Last Modification Time",
"DisplayName:WebhookEvent": "Event",
"DisplayName:BeginCreationTime": "Begin Creation Time",
"DisplayName:EndCreationTime": "End Creation Time",
"DisplayName:SendExactSameData": "Send Exact Same Data",
"DisplayName:Header": "Header",
"DisplayName:UseOnlyGivenHeaders": "Use Only Given Headers",
"DisplayName:TenantId": "Tenant Id",
"DisplayName:TenantIds": "Tenant Ids",
"DisplayName:WebhookUri": "Uri",
"DisplayName:Secret": "Secret",
"DisplayName:IsActive": "Is Active",
"DisplayName:Webhooks": "Webhooks",
"DisplayName:Headers": "Headers"
} }
} }

34
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain.Shared/LINGYUN/Abp/WebhooksManagement/Localization/Resources/zh-Hans.json

@ -14,6 +14,38 @@
"Webhooks:010001": "载荷地址 {WebhookUri} 已经挂载事件 {Webhooks}!", "Webhooks:010001": "载荷地址 {WebhookUri} 已经挂载事件 {Webhooks}!",
"Webhooks:Tests": "测试", "Webhooks:Tests": "测试",
"Webhooks:CheckConnect": "检查连接", "Webhooks:CheckConnect": "检查连接",
"Webhooks:CheckConnectDesc": "第三方服务接入时,用于检查是否通讯正常." "Webhooks:CheckConnectDesc": "第三方服务接入时,用于检查是否通讯正常.",
"SendAttempts": "发送记录",
"BasicInfo": "基本信息",
"Subscriptions": "订阅者",
"WebhookEvent": "事件",
"Subscriptions:AddNew": "添加订阅",
"Subscriptions:Edit": "编辑订阅",
"Resend": "重新发送",
"DisplayName:Name": "名称",
"DisplayName:DisplayName": "显示名称",
"DisplayName:Description": "描述",
"DisplayName:WebhookName": "事件名称",
"DisplayName:Subscription": "订阅者",
"DisplayName:Data": "事件数据",
"DisplayName:CreationTime": "创建时间",
"DisplayName:WebhookEventId": "事件标识",
"DisplayName:WebhookSubscriptionId": "订阅者标识",
"DisplayName:Response": "响应正文",
"DisplayName:ResponseStatusCode": "响应代码",
"DisplayName:LastModificationTime": "最近变更时间",
"DisplayName:WebhookEvent": "事件明细",
"DisplayName:BeginCreationTime": "起始创建时间",
"DisplayName:EndCreationTime": "截止创建时间",
"DisplayName:SendExactSameData": "发送原数据",
"DisplayName:Header": "标头",
"DisplayName:UseOnlyGivenHeaders": "只使用给定标头",
"DisplayName:TenantId": "租户",
"DisplayName:TenantIds": "租户列表",
"DisplayName:WebhookUri": "服务器地址",
"DisplayName:Secret": "密钥",
"DisplayName:IsActive": "是否启用",
"DisplayName:Webhooks": "事件列表",
"DisplayName:Headers": "发送标头"
} }
} }

3
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookEventRecord.cs

@ -2,11 +2,10 @@
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.WebhooksManagement; namespace LINGYUN.Abp.WebhooksManagement;
public class WebhookEventRecord : Entity<Guid>, IMultiTenant, IHasCreationTime, IHasDeletionTime public class WebhookEventRecord : Entity<Guid>, IHasCreationTime, IHasDeletionTime
{ {
public virtual Guid? TenantId { get; protected set; } public virtual Guid? TenantId { get; protected set; }
public virtual string WebhookName { get; protected set; } public virtual string WebhookName { get; protected set; }

3
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSendRecord.cs

@ -3,11 +3,10 @@ using System.Net;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.WebhooksManagement; namespace LINGYUN.Abp.WebhooksManagement;
public class WebhookSendRecord : Entity<Guid>, IHasCreationTime, IHasModificationTime, IMultiTenant public class WebhookSendRecord : Entity<Guid>, IHasCreationTime, IHasModificationTime
{ {
public virtual Guid? TenantId { get; protected set; } public virtual Guid? TenantId { get; protected set; }

2
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.Domain/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordFilter.cs

@ -7,6 +7,8 @@ public class WebhookSendRecordFilter
{ {
public string Filter { get; set; } public string Filter { get; set; }
public Guid? TenantId { get; set; }
public Guid? WebhookEventId { get; set; } public Guid? WebhookEventId { get; set; }
public Guid? SubscriptionId { get; set; } public Guid? SubscriptionId { get; set; }

1
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore/LINGYUN/Abp/WebhooksManagement/EntityFrameworkCore/EfCoreWebhookSendRecordRepository.cs

@ -53,6 +53,7 @@ public class EfCoreWebhookSendRecordRepository :
WebhookSendRecordFilter filter) WebhookSendRecordFilter filter)
{ {
return queryable return queryable
.WhereIf(filter.TenantId.HasValue, x => x.TenantId == filter.TenantId)
.WhereIf(filter.WebhookEventId.HasValue, x => x.WebhookEventId == filter.WebhookEventId) .WhereIf(filter.WebhookEventId.HasValue, x => x.WebhookEventId == filter.WebhookEventId)
.WhereIf(filter.SubscriptionId.HasValue, x => x.WebhookSubscriptionId == filter.SubscriptionId) .WhereIf(filter.SubscriptionId.HasValue, x => x.WebhookSubscriptionId == filter.SubscriptionId)
.WhereIf(filter.ResponseStatusCode.HasValue, x => x.ResponseStatusCode == filter.ResponseStatusCode) .WhereIf(filter.ResponseStatusCode.HasValue, x => x.ResponseStatusCode == filter.ResponseStatusCode)

14
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.HttpApi/LINGYUN/Abp/WebhooksManagement/WebhookSendRecordController.cs

@ -23,13 +23,21 @@ public class WebhookSendRecordController : WebhooksManagementControllerBase, IWe
[HttpGet] [HttpGet]
[Route("{id}")] [Route("{id}")]
public Task<WebhookSendRecordDto> GetAsync(Guid id) public virtual Task<WebhookSendRecordDto> GetAsync(Guid id)
{ {
return SendRecordAppService.GetAsync(id); return SendRecordAppService.GetAsync(id);
} }
[HttpDelete]
[Route("{id}")]
[Authorize(WebhooksManagementPermissions.WebhooksSendAttempts.Delete)]
public virtual Task DeleteAsync(Guid id)
{
return SendRecordAppService.DeleteAsync(id);
}
[HttpGet] [HttpGet]
public Task<PagedResultDto<WebhookSendRecordDto>> GetListAsync(WebhookSendRecordGetListInput input) public virtual Task<PagedResultDto<WebhookSendRecordDto>> GetListAsync(WebhookSendRecordGetListInput input)
{ {
return SendRecordAppService.GetListAsync(input); return SendRecordAppService.GetListAsync(input);
} }
@ -37,7 +45,7 @@ public class WebhookSendRecordController : WebhooksManagementControllerBase, IWe
[HttpPost] [HttpPost]
[Route("{id}/resend")] [Route("{id}/resend")]
[Authorize(WebhooksManagementPermissions.WebhooksSendAttempts.Resend)] [Authorize(WebhooksManagementPermissions.WebhooksSendAttempts.Resend)]
public Task ResendAsync(Guid id) public virtual Task ResendAsync(Guid id)
{ {
return SendRecordAppService.ResendAsync(id); return SendRecordAppService.ResendAsync(id);
} }

12
aspnet-core/modules/webhooks/LINGYUN.Abp.WebhooksManagement.HttpApi/LINGYUN/Abp/WebhooksManagement/WebhookSubscriptionController.cs

@ -23,7 +23,7 @@ public class WebhookSubscriptionController : WebhooksManagementControllerBase, I
[HttpPost] [HttpPost]
[Authorize(WebhooksManagementPermissions.WebhookSubscription.Create)] [Authorize(WebhooksManagementPermissions.WebhookSubscription.Create)]
public Task<WebhookSubscriptionDto> CreateAsync(WebhookSubscriptionCreateInput input) public virtual Task<WebhookSubscriptionDto> CreateAsync(WebhookSubscriptionCreateInput input)
{ {
return SubscriptionAppService.CreateAsync(input); return SubscriptionAppService.CreateAsync(input);
} }
@ -31,20 +31,20 @@ public class WebhookSubscriptionController : WebhooksManagementControllerBase, I
[HttpDelete] [HttpDelete]
[Route("{id}")] [Route("{id}")]
[Authorize(WebhooksManagementPermissions.WebhookSubscription.Delete)] [Authorize(WebhooksManagementPermissions.WebhookSubscription.Delete)]
public Task DeleteAsync(Guid id) public virtual Task DeleteAsync(Guid id)
{ {
return SubscriptionAppService.DeleteAsync(id); return SubscriptionAppService.DeleteAsync(id);
} }
[HttpGet] [HttpGet]
[Route("{id}")] [Route("{id}")]
public Task<WebhookSubscriptionDto> GetAsync(Guid id) public virtual Task<WebhookSubscriptionDto> GetAsync(Guid id)
{ {
return SubscriptionAppService.GetAsync(id); return SubscriptionAppService.GetAsync(id);
} }
[HttpGet] [HttpGet]
public Task<PagedResultDto<WebhookSubscriptionDto>> GetListAsync(WebhookSubscriptionGetListInput input) public virtual Task<PagedResultDto<WebhookSubscriptionDto>> GetListAsync(WebhookSubscriptionGetListInput input)
{ {
return SubscriptionAppService.GetListAsync(input); return SubscriptionAppService.GetListAsync(input);
} }
@ -52,14 +52,14 @@ public class WebhookSubscriptionController : WebhooksManagementControllerBase, I
[HttpPut] [HttpPut]
[Route("{id}")] [Route("{id}")]
[Authorize(WebhooksManagementPermissions.WebhookSubscription.Update)] [Authorize(WebhooksManagementPermissions.WebhookSubscription.Update)]
public Task<WebhookSubscriptionDto> UpdateAsync(Guid id, WebhookSubscriptionUpdateInput input) public virtual Task<WebhookSubscriptionDto> UpdateAsync(Guid id, WebhookSubscriptionUpdateInput input)
{ {
return SubscriptionAppService.UpdateAsync(id, input); return SubscriptionAppService.UpdateAsync(id, input);
} }
[HttpGet] [HttpGet]
[Route("availables")] [Route("availables")]
public Task<ListResultDto<WebhookAvailableGroupDto>> GetAllAvailableWebhooksAsync() public virtual Task<ListResultDto<WebhookAvailableGroupDto>> GetAllAvailableWebhooksAsync()
{ {
return SubscriptionAppService.GetAllAvailableWebhooksAsync(); return SubscriptionAppService.GetAllAvailableWebhooksAsync();
} }

2
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/Properties/launchSettings.json

@ -14,7 +14,7 @@
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}, },
"applicationUrl": "http://127.0.0.1:30045", "applicationUrl": "http://0.0.0.0:30045",
"dotnetRunMessages": "true" "dotnetRunMessages": "true"
} }
} }

4
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/Ocelot/Configuration/Repository/DiskFileConfigurationAggragatorRepository.cs

@ -43,7 +43,9 @@ namespace LINGYUN.MicroService.Internal.ApiGateway.Ocelot.Configuration.Reposito
"ocelot.localization.json", "ocelot.localization.json",
"ocelot.messages.json", "ocelot.messages.json",
"ocelot.platform.json", "ocelot.platform.json",
"ocelot.aggregate.json" "ocelot.aggregate.json",
"ocelot.task.json",
"ocelot.webhook.json"
}; };
} }

60
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.Development.json

@ -1626,6 +1626,63 @@
"HttpHandlerOptions": {}, "HttpHandlerOptions": {},
"DangerousAcceptAnyServerCertificateValidator": true, "DangerousAcceptAnyServerCertificateValidator": true,
"RouteIsCaseSensitive": false "RouteIsCaseSensitive": false
},
{
"DownstreamPathTemplate": "/api/abp/api-definition",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 30045
}
],
"UpstreamPathTemplate": "/api/abp/webhook/api-definition",
"UpstreamHttpMethod": [
"GET"
],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"RateLimitOptions": {},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 10,
"DurationOfBreak": 1000,
"TimeoutValue": 10000
},
"HttpHandlerOptions": {
"UseTracing": true
},
"Key": "webhook-api-definition"
},
{
"DownstreamPathTemplate": "/api/webhooks/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 30045
}
],
"UpstreamPathTemplate": "/api/webhooks/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": true,
"Period": "1s",
"PeriodTimespan": 1,
"Limit": 5
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 10,
"DurationOfBreak": 1000,
"TimeoutValue": 10000
},
"HttpHandlerOptions": {
"UseTracing": true
}
} }
], ],
"Aggregates": [ "Aggregates": [
@ -1636,7 +1693,8 @@
"messages-api-definition", "messages-api-definition",
"ids-admin-api-definition", "ids-admin-api-definition",
"localization-api-definition", "localization-api-definition",
"task-api-definition" "task-api-definition",
"webhook-api-definition"
], ],
"UpstreamPathTemplate": "/api/abp/api-definition", "UpstreamPathTemplate": "/api/abp/api-definition",
"Aggregator": "AbpResponseMergeAggregator" "Aggregator": "AbpResponseMergeAggregator"

13
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.aggregate.json

@ -1,6 +1,6 @@
{ {
"Aggregates": [ "Aggregates": [
// // ̬ۺ
{ {
"RouteKeys": [ "RouteKeys": [
"platform-api-definition", "platform-api-definition",
@ -8,13 +8,14 @@
"messages-api-definition", "messages-api-definition",
"ids-admin-api-definition", "ids-admin-api-definition",
"localization-api-definition", "localization-api-definition",
"task-api-definition" "task-api-definition",
"webhook-api-definition"
], ],
"UpstreamPathTemplate": "/api/abp/api-definition", "UpstreamPathTemplate": "/api/abp/api-definition",
"Aggregator": "AbpResponseMergeAggregator", "Aggregator": "AbpResponseMergeAggregator",
"Priority": 99 "Priority": 99
}, },
// // þۺ
{ {
"RouteKeys": [ "RouteKeys": [
"platform-configuration", "platform-configuration",
@ -28,7 +29,7 @@
"Aggregator": "AbpResponseMergeAggregator", "Aggregator": "AbpResponseMergeAggregator",
"Priority": 99 "Priority": 99
}, },
// // ȫ
{ {
"RouteKeys": [ "RouteKeys": [
"setting-global", "setting-global",
@ -40,7 +41,7 @@
"Aggregator": "AbpResponseMergeAggregator", "Aggregator": "AbpResponseMergeAggregator",
"Priority": 99 "Priority": 99
}, },
// //
{ {
"RouteKeys": [ "RouteKeys": [
"setting-current-tenant", "setting-current-tenant",
@ -52,7 +53,7 @@
"Aggregator": "AbpResponseMergeAggregator", "Aggregator": "AbpResponseMergeAggregator",
"Priority": 99 "Priority": 99
}, },
// // û
{ {
"RouteKeys": [ "RouteKeys": [
"assignables-notifilers", "assignables-notifilers",

59
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.webhook.json

@ -0,0 +1,59 @@
{
"Routes": [
{
"DownstreamPathTemplate": "/api/abp/api-definition",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 30045
}
],
"UpstreamPathTemplate": "/api/abp/webhook/api-definition",
"UpstreamHttpMethod": [ "GET" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"RateLimitOptions": {},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 10,
"DurationOfBreak": 1000,
"TimeoutValue": 10000
},
"HttpHandlerOptions": {
"UseTracing": true
},
"Key": "webhook-api-definition"
},
{
"DownstreamPathTemplate": "/api/webhooks/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 30045
}
],
"UpstreamPathTemplate": "/api/webhooks/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": true,
"Period": "1s",
"PeriodTimespan": 1,
"Limit": 5
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 10,
"DurationOfBreak": 1000,
"TimeoutValue": 10000
},
"HttpHandlerOptions": {
"UseTracing": true
}
}
]
}
Loading…
Cancel
Save