Files
Maries 4589841b0c feat: introduce trigger (#482)
* feat(plugins): add FetchPluginReadme endpoint and update launch configurations

* feat: add PluginReadme database model

* feat: implement readme extracting and storage

* feat: implement readme endpoint

* feat: add plugin asset extraction endpoint with caching support

* Implement trigger functionality and clean up dynamic select code

- Added new trigger-related access types and actions in access.go.
- Introduced new HTTP routes for trigger operations in http_server.gen.go.
- Updated plugin declaration to include triggers in plugin_entities.
- Removed unused dynamic select service and controller files.
- Enhanced message handling in debugging_runtime to support trigger registration.

This update enhances the plugin system by integrating trigger capabilities while cleaning up legacy code.

* Refactor trigger-related types and enhance dynamic select functionality

- Updated TriggerProviderIdentity and TriggerProviderConfiguration to improve structure and validation.
- Renamed TriggerConfiguration to TriggerDeclaration for clarity.
- Added CredentialType to RequestDynamicParameterSelect for better request handling.
- Enhanced PluginDecoderHelper to read and unmarshal trigger files correctly.

These changes streamline the trigger system and improve the overall request handling in the plugin architecture.

* Add trigger functionality and enhance database integration

- Introduced TriggerInstallation model for managing trigger installations in the database.
- Updated autoMigrate function to include trigger installations in the migration process.
- Added new HTTP routes for listing and retrieving triggers in the HTTP server.
- Implemented ListTriggers and GetTrigger controller functions for handling trigger requests.
- Enhanced plugin management functions to create, update, and delete trigger installations during plugin lifecycle events.

These changes integrate trigger capabilities into the system, improving the overall plugin functionality and management.

* feat: add remapping for trigger icons in MediaBucket

- Enhanced the RemapAssets function to include remapping of trigger identity icons and dark icons.
- Added error handling for remapping failures to ensure robust asset management.

These changes improve the handling of trigger assets within the plugin system, ensuring icons are correctly remapped as needed.

* feat: add Multiple field to TriggerParameter for enhanced configuration

- Introduced a new Multiple field in the TriggerParameter struct to allow for multiple values in trigger configurations.
- This addition improves the flexibility of trigger parameters within the plugin system.

These changes enhance the capability of trigger parameters, enabling more complex configurations.

* feat: add Multiple field to ProviderConfig for enhanced configuration

- Introduced a new Multiple field in the ProviderConfig struct to allow for multiple values in provider configurations.
- This addition improves the flexibility of provider options within the plugin system.

These changes enhance the capability of provider configurations, enabling more complex setups.

* fix(plugin): update validation error messages in ManifestValidate method

- Enhanced error messages in the ManifestValidate function to include 'trigger' in the validation checks for plugin declarations.
- Updated logic to ensure that all relevant fields are considered when validating the presence of mutually exclusive parameters.

* feat(trigger): add CHECKBOX parameter type to plugin entities  and refactor the trigger provider strcuture

- Introduced a new CHECKBOX parameter type in constant.go for plugin entities.
- Updated tool_declaration.go and trigger_declaration.go to include TOOL_PARAMETER_TYPE_CHECKBOX and TRIGGER_PARAMETER_TYPE_CHECKBOX respectively.
- Enhanced validation logic to accommodate the new CHECKBOX type in parameter checks.

* fix(trigger): update SubscriptionSchema validation in TriggerProviderDeclaration

- Changed SubscriptionSchema validation from 'omitempty' to 'required' in TriggerProviderDeclaration to ensure it is always provided.
- Updated SubscriptionConstructor field to be a pointer to allow for optional inclusion in the trigger provider configuration.

* fix(trigger): rename ParametersSchema to Parameters in SubscriptionConstructor

- Updated the SubscriptionConstructor struct to rename the ParametersSchema field to Parameters for consistency.
- Adjusted related JSON and YAML marshaling logic to reflect the new field name, ensuring proper handling of trigger parameters.

* refactor(trigger): enhance YAML unmarshalling for SubscriptionConstructor and SubscriptionSchema

- Introduced a new helper function to convert YAML nodes to ProviderConfig lists, improving the handling of subscription_schema and credentials_schema.
- Updated the UnmarshalYAML method to utilize the new function, simplifying the logic for parsing different YAML formats.
- Ensured proper initialization of SubscriptionConstructor fields to prevent nil pointer dereferences.

* fix(trigger): update SubscriptionConstructor validation in TriggerProviderDeclaration

- Changed the validation for SubscriptionConstructor in TriggerProviderDeclaration from 'omitempty,dive' to 'omitempty' to simplify the validation logic.
- Ensured that the SubscriptionConstructor field remains optional while maintaining its intended functionality.

* refactor(trigger): rename Trigger to Event in plugin entities and related structures

- Updated the naming conventions in trigger_declaration.go to replace 'Trigger' with 'Event' for better clarity and consistency.
- Adjusted related types, validation functions, and unmarshalling logic to reflect the new 'Event' terminology.
- Ensured that all references to triggers in the codebase are updated to events, including in the SubscriptionConstructor and response structures.

* refactor(trigger): rename TriggerInvoke to TriggerInvokeEvent and update related structures

- Renamed TriggerInvoke function and associated request/response types to TriggerInvokeEvent for improved clarity.
- Updated routing and controller methods to reflect the new naming convention.
- Ensured all references to the trigger invoke functionality are consistent with the new event terminology.

* refactor(trigger): remove Subscription struct from trigger_declaration.go and update TriggerDispatchEventRequest

- Removed the Subscription struct from trigger_declaration.go to streamline the codebase.
- Added Credentials field to TriggerDispatchEventRequest for enhanced functionality and clarity.
- Ensured that the changes maintain consistency with the existing naming conventions and structures.

* fix(trigger): improve nil checks for SubscriptionConstructor in TriggerProviderDeclaration

- Added nil checks for SubscriptionConstructor before accessing its fields to prevent potential nil pointer dereferences.
- Ensured that Parameters and CredentialsSchema are initialized only if SubscriptionConstructor is not nil, enhancing code robustness.

* fix(plugin): add recovery mechanism in OnTraffic to handle panics

- Introduced a deferred function in OnTraffic to recover from panics, logging the error and stack trace for better debugging.
- This enhancement improves the stability of the DifyServer by preventing crashes due to unexpected runtime errors.

* feat(trigger): add Subscription field to TriggerInvokeEventRequest

- Introduced a new Subscription field in the TriggerInvokeEventRequest struct to accommodate subscription data.
- Ensured the field is marked as required, enhancing the request's functionality and validation requirements.

* refactor(event): simplify EventDescription structure in EventDeclaration

- Removed the EventDescription struct and replaced it with a direct I18nObject field in EventDeclaration.
- This change streamlines the event configuration by reducing complexity while maintaining required validation for the description.

* feat(trigger): add UserID field to TriggerDispatchEventResponse

- Introduced a new UserID field in the TriggerDispatchEventResponse struct to include user identification in the response.
- The field is marked as optional, enhancing the response's flexibility while maintaining existing functionality.

* feat: add payload to TriggerDispatchEventResponse

* fix

* feat(trigger): update TriggerDispatchEventResponse structure

* fix: avoid path collusion

* fix: missing )

* fix: query param

* fix: form param

* fix: remove redundant dynamic parameter access type

* fix: remove dynamic parameter access type from validation

* Update internal/server/controllers/plugins.go

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: Stream <Stream_2@qq.com>
Co-authored-by: Yeuoly <admin@srmxy.cn>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-29 13:56:58 +08:00

179 lines
4.4 KiB
Go

package plugin_entities
import (
"testing"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
)
func TestConvertYAMLNodeToProviderConfigList(t *testing.T) {
tests := []struct {
name string
yamlStr string
expected []ProviderConfig
wantErr bool
}{
{
name: "array format",
yamlStr: `
- name: api_key
type: string
required: true
- name: endpoint
type: string
required: false`,
expected: []ProviderConfig{
{Name: "api_key", Type: "string", Required: true},
{Name: "endpoint", Type: "string", Required: false},
},
wantErr: false,
},
{
name: "dict format",
yamlStr: `
api_key:
type: string
required: true
endpoint:
type: string
required: false`,
expected: []ProviderConfig{
{Name: "api_key", Type: "string", Required: true},
{Name: "endpoint", Type: "string", Required: false},
},
wantErr: false,
},
{
name: "empty array",
yamlStr: `[]`,
expected: []ProviderConfig{},
wantErr: false,
},
{
name: "empty dict",
yamlStr: `{}`,
expected: []ProviderConfig{},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var node yaml.Node
err := yaml.Unmarshal([]byte(tt.yamlStr), &node)
assert.NoError(t, err)
// The unmarshal creates a Document node, we need its content
contentNode := node.Content[0]
result, err := convertYAMLNodeToProviderConfigList(contentNode)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.expected, result)
}
})
}
}
func TestTriggerProviderDeclaration_UnmarshalYAML(t *testing.T) {
tests := []struct {
name string
yamlStr string
check func(t *testing.T, declaration *TriggerProviderDeclaration)
wantErr bool
}{
{
name: "subscription_schema with dict format",
yamlStr: `
identity:
name: test_provider
author: test_author
subscription_schema:
api_key:
type: string
required: true
secret:
type: password
required: true`,
check: func(t *testing.T, d *TriggerProviderDeclaration) {
assert.Len(t, d.SubscriptionSchema, 2)
assert.Equal(t, "api_key", d.SubscriptionSchema[0].Name)
assert.Equal(t, ConfigType("string"), d.SubscriptionSchema[0].Type)
assert.True(t, d.SubscriptionSchema[0].Required)
assert.Equal(t, "secret", d.SubscriptionSchema[1].Name)
assert.Equal(t, ConfigType("password"), d.SubscriptionSchema[1].Type)
},
wantErr: false,
},
{
name: "subscription_constructor.credentials_schema with dict format",
yamlStr: `
identity:
name: test_provider
author: test_author
subscription_schema:
- name: webhook_url
type: string
required: true
subscription_constructor:
credentials_schema:
client_id:
type: string
required: true
client_secret:
type: password
required: true`,
check: func(t *testing.T, d *TriggerProviderDeclaration) {
assert.NotNil(t, d.SubscriptionConstructor)
assert.Len(t, d.SubscriptionConstructor.CredentialsSchema, 2)
assert.Equal(t, "client_id", d.SubscriptionConstructor.CredentialsSchema[0].Name)
assert.Equal(t, ConfigType("string"), d.SubscriptionConstructor.CredentialsSchema[0].Type)
assert.Equal(t, "client_secret", d.SubscriptionConstructor.CredentialsSchema[1].Name)
assert.Equal(t, ConfigType("password"), d.SubscriptionConstructor.CredentialsSchema[1].Type)
},
wantErr: false,
},
{
name: "mixed formats - dict subscription_schema and array credentials_schema",
yamlStr: `
identity:
name: test_provider
author: test_author
subscription_schema:
webhook_url:
type: string
required: true
subscription_constructor:
credentials_schema:
- name: api_key
type: string
required: true`,
check: func(t *testing.T, d *TriggerProviderDeclaration) {
assert.Len(t, d.SubscriptionSchema, 1)
assert.Equal(t, "webhook_url", d.SubscriptionSchema[0].Name)
assert.NotNil(t, d.SubscriptionConstructor)
assert.Len(t, d.SubscriptionConstructor.CredentialsSchema, 1)
assert.Equal(t, "api_key", d.SubscriptionConstructor.CredentialsSchema[0].Name)
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var declaration TriggerProviderDeclaration
err := yaml.Unmarshal([]byte(tt.yamlStr), &declaration)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
tt.check(t, &declaration)
}
})
}
}