Skip to content

Commit 82b7fb0

Browse files
committed
3827 Additional fixes
1 parent 9101f2b commit 82b7fb0

File tree

13 files changed

+1105
-51
lines changed

13 files changed

+1105
-51
lines changed

server/libs/modules/components/form/src/main/java/com/bytechef/component/form/constant/FormConstants.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ public class FormConstants {
3232
public static final String FIELD_TYPE = "fieldType";
3333
public static final String FORM = "form";
3434
public static final String FORM_DESCRIPTION = "formDescription";
35-
// public static final String FORM_PATH = "formPath";
3635
public static final String FORM_TITLE = "formTitle";
3736
public static final String IGNORE_BOTS = "ignoreBots";
3837
public static final String INPUTS = "inputs";
@@ -68,8 +67,8 @@ public int getValue() {
6867
return value;
6968
}
7069

71-
public static FieldType valueOf(int value) {
72-
for (FieldType fieldType : FieldType.values()) {
70+
public static FieldType fromValue(int value) {
71+
for (FieldType fieldType : values()) {
7372
if (fieldType.value == value) {
7473
return fieldType;
7574
}

server/libs/modules/components/form/src/main/java/com/bytechef/component/form/trigger/NewFormRequestTrigger.java

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,20 @@
3939
import static com.bytechef.component.form.constant.FormConstants.FIELD_TYPE;
4040
import static com.bytechef.component.form.constant.FormConstants.FORM_DESCRIPTION;
4141
import static com.bytechef.component.form.constant.FormConstants.FORM_TITLE;
42-
import static com.bytechef.component.form.constant.FormConstants.FieldType.*;
4342
import static com.bytechef.component.form.constant.FormConstants.FieldType.CHECKBOX;
4443
import static com.bytechef.component.form.constant.FormConstants.FieldType.CUSTOM_HTML;
44+
import static com.bytechef.component.form.constant.FormConstants.FieldType.DATETIME_PICKER;
45+
import static com.bytechef.component.form.constant.FormConstants.FieldType.DATE_PICKER;
46+
import static com.bytechef.component.form.constant.FormConstants.FieldType.EMAIL_INPUT;
47+
import static com.bytechef.component.form.constant.FormConstants.FieldType.FILE_INPUT;
48+
import static com.bytechef.component.form.constant.FormConstants.FieldType.HIDDEN_FIELD;
49+
import static com.bytechef.component.form.constant.FormConstants.FieldType.INPUT;
50+
import static com.bytechef.component.form.constant.FormConstants.FieldType.NUMBER_INPUT;
51+
import static com.bytechef.component.form.constant.FormConstants.FieldType.PASSWORD_INPUT;
52+
import static com.bytechef.component.form.constant.FormConstants.FieldType.RADIO;
53+
import static com.bytechef.component.form.constant.FormConstants.FieldType.SELECT;
54+
import static com.bytechef.component.form.constant.FormConstants.FieldType.TEXTAREA;
55+
import static com.bytechef.component.form.constant.FormConstants.FieldType.fromValue;
4556
import static com.bytechef.component.form.constant.FormConstants.IGNORE_BOTS;
4657
import static com.bytechef.component.form.constant.FormConstants.INPUTS;
4758
import static com.bytechef.component.form.constant.FormConstants.MAX_SELECTION;
@@ -91,10 +102,6 @@ public class NewFormRequestTrigger {
91102
.label("Form Description")
92103
.description("A subtitle shown under the form title. Use \n or <br> for line breaks.")
93104
.required(false),
94-
// string(FORM_PATH)
95-
// .label("Form Path")
96-
// .description("Custom slug for the form URL path.")
97-
// .required(false),
98105
string(BUTTON_LABEL)
99106
.label("Button Label")
100107
.description("Label for the submit button.")
@@ -159,7 +166,8 @@ public class NewFormRequestTrigger {
159166
.description("The placeholder text.")
160167
.required(false)
161168
.displayCondition("contains({%s,%s,%s,%s,%s}, fieldType)".formatted(
162-
EMAIL_INPUT, INPUT, NUMBER_INPUT, PASSWORD_INPUT, TEXTAREA)),
169+
EMAIL_INPUT.getValue(), INPUT.getValue(), NUMBER_INPUT.getValue(),
170+
PASSWORD_INPUT.getValue(), TEXTAREA.getValue())),
163171
string(DEFAULT_VALUE)
164172
.label("Default value")
165173
.description("Pre-filled or pre-selected value for compatible fields.")
@@ -185,14 +193,14 @@ public class NewFormRequestTrigger {
185193
.required(true)))
186194
.required(false)
187195
.displayCondition(
188-
"contains({%s,%s}, provider)".formatted(RADIO.getValue(), SELECT.getValue())),
196+
"contains({%s,%s}, fieldType)".formatted(RADIO.getValue(), SELECT.getValue())),
189197
bool(MULTIPLE_CHOICE)
190198
.label("Multiple Choice")
191199
.description("Allow multiple selections.")
192200
.defaultValue(false)
193201
.required(false)
194202
.displayCondition(
195-
"fieldType == %s and multipleChoice == true".formatted(SELECT.getValue())),
203+
"fieldType == %s".formatted(SELECT.getValue())),
196204
integer(MIN_SELECTION)
197205
.label("Min selection")
198206
.description("Minimum selections required.")
@@ -203,7 +211,8 @@ public class NewFormRequestTrigger {
203211
.label("Max selection")
204212
.description("Maximum selections allowed.")
205213
.required(false)
206-
.displayCondition("fieldType == %s".formatted(CHECKBOX.getValue())),
214+
.displayCondition(
215+
"fieldType == %s and multipleChoice == true".formatted(SELECT.getValue())),
207216
bool(REQUIRED)
208217
.label("Required")
209218
.description("Whether this field is required")
@@ -230,7 +239,8 @@ protected static OutputResponse getOutput(
230239
}
231240

232241
Integer fieldTypeInt = (Integer) input.get(FIELD_TYPE);
233-
FieldType fieldType = valueOf(fieldTypeInt);
242+
243+
FieldType fieldType = fieldTypeInt != null ? fromValue(fieldTypeInt) : INPUT;
234244

235245
ModifiableValueProperty<?, ?> property = switch (fieldType) {
236246
case CHECKBOX -> bool(fieldName);
@@ -253,7 +263,7 @@ protected static OutputResponse getOutput(
253263
return OutputResponse.of(
254264
object()
255265
.properties(
256-
number("submittedAt"),
266+
string("submittedAt"),
257267
object("body")
258268
.properties(properties.toArray(new ModifiableValueProperty[0]))));
259269
}
@@ -279,14 +289,14 @@ protected static OutputResponse getOutput(
279289
}
280290

281291
@SuppressWarnings("unchecked")
282-
Map<String, Object> bodyContent = new HashMap<>((Map<String, Object>) body.getContent());
292+
Map<String, Object> content = new HashMap<>((Map<String, Object>) body.getContent());
283293

284294
boolean useWorkflowTimezone = inputParameters.getBoolean(USE_WORKFLOW_TIMEZONE, false);
285295

286296
if (!useWorkflowTimezone) {
287-
bodyContent.put("submittedAt", String.valueOf(Instant.now(Clock.systemUTC())));
297+
content.put("submittedAt", String.valueOf(Instant.now(Clock.systemUTC())));
288298
}
289299

290-
return bodyContent;
300+
return content;
291301
}
292302
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2025 ByteChef
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.bytechef.component.form;
18+
19+
import com.bytechef.test.jsonasssert.JsonFileAssert;
20+
import org.junit.jupiter.api.Test;
21+
22+
/**
23+
* @author Ivica Cardic
24+
*/
25+
public class FormComponentHandlerTest {
26+
27+
@Test
28+
public void testGetDefinition() {
29+
JsonFileAssert.assertEquals("definition/form_v1.json", new FormComponentHandler().getDefinition());
30+
}
31+
}
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*
2+
* Copyright 2025 ByteChef
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.bytechef.component.form.trigger;
18+
19+
import static com.bytechef.component.form.constant.FormConstants.FIELD_NAME;
20+
import static com.bytechef.component.form.constant.FormConstants.FIELD_TYPE;
21+
import static com.bytechef.component.form.constant.FormConstants.IGNORE_BOTS;
22+
import static com.bytechef.component.form.constant.FormConstants.INPUTS;
23+
import static com.bytechef.component.form.constant.FormConstants.MULTIPLE_CHOICE;
24+
import static com.bytechef.component.form.constant.FormConstants.USE_WORKFLOW_TIMEZONE;
25+
import static org.junit.jupiter.api.Assertions.assertEquals;
26+
import static org.junit.jupiter.api.Assertions.assertFalse;
27+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
28+
import static org.junit.jupiter.api.Assertions.assertNotNull;
29+
import static org.junit.jupiter.api.Assertions.assertTrue;
30+
import static org.mockito.Mockito.mock;
31+
import static org.mockito.Mockito.when;
32+
33+
import com.bytechef.component.definition.Parameters;
34+
import com.bytechef.component.definition.TriggerContext;
35+
import com.bytechef.component.definition.TriggerDefinition.HttpHeaders;
36+
import com.bytechef.component.definition.TriggerDefinition.HttpParameters;
37+
import com.bytechef.component.definition.TriggerDefinition.WebhookBody;
38+
import com.bytechef.component.definition.TriggerDefinition.WebhookMethod;
39+
import com.bytechef.component.form.constant.FormConstants.FieldType;
40+
import com.bytechef.component.test.definition.MockParametersFactory;
41+
import com.bytechef.definition.BaseOutputDefinition.OutputResponse;
42+
import com.bytechef.definition.BaseProperty;
43+
import com.bytechef.definition.BaseProperty.BaseObjectProperty;
44+
import java.util.List;
45+
import java.util.Map;
46+
import java.util.Optional;
47+
import org.junit.jupiter.api.Test;
48+
49+
/**
50+
* @author Ivica Cardic
51+
*/
52+
class NewFormRequestTriggerTest {
53+
54+
private final TriggerContext mockedTriggerContext = mock(TriggerContext.class);
55+
private final HttpHeaders mockedHttpHeaders = mock(HttpHeaders.class);
56+
private final HttpParameters mockedHttpParameters = mock(HttpParameters.class);
57+
private final WebhookBody mockedWebhookBody = mock(WebhookBody.class);
58+
private final WebhookMethod mockedWebhookMethod = mock(WebhookMethod.class);
59+
private final Parameters mockedWebhookEnableOutput = mock(Parameters.class);
60+
61+
@Test
62+
void testGetOutput() {
63+
Parameters inputParameters = MockParametersFactory.create(
64+
Map.of(
65+
INPUTS, List.of(
66+
Map.of(FIELD_NAME, "field1", FIELD_TYPE, FieldType.CHECKBOX.getValue()),
67+
Map.of(FIELD_NAME, "field2", FIELD_TYPE, FieldType.DATE_PICKER.getValue()),
68+
Map.of(FIELD_NAME, "field3", FIELD_TYPE, FieldType.DATETIME_PICKER.getValue()),
69+
Map.of(FIELD_NAME, "field4", FIELD_TYPE, FieldType.FILE_INPUT.getValue()),
70+
Map.of(FIELD_NAME, "field5", FIELD_TYPE, FieldType.NUMBER_INPUT.getValue()),
71+
Map.of(FIELD_NAME, "field6", FIELD_TYPE, FieldType.SELECT.getValue(), MULTIPLE_CHOICE, true),
72+
Map.of(FIELD_NAME, "field7", FIELD_TYPE, FieldType.SELECT.getValue(), MULTIPLE_CHOICE, false),
73+
Map.of(FIELD_NAME, "field8", FIELD_TYPE, FieldType.INPUT.getValue()),
74+
Map.of(FIELD_TYPE, FieldType.INPUT.getValue()) // Missing field name
75+
)));
76+
77+
OutputResponse outputResponse = NewFormRequestTrigger.getOutput(
78+
inputParameters, mock(Parameters.class), mockedTriggerContext);
79+
80+
assertNotNull(outputResponse);
81+
82+
BaseProperty.BaseValueProperty<?> outputSchema = outputResponse.getOutputSchema();
83+
assertInstanceOf(BaseObjectProperty.class, outputSchema);
84+
85+
BaseObjectProperty<?> objectProperty = (BaseObjectProperty<?>) outputSchema;
86+
87+
List<? extends BaseProperty> properties = objectProperty.getProperties()
88+
.orElseThrow();
89+
90+
assertEquals(2, properties.size());
91+
92+
BaseProperty property1 = properties.get(0);
93+
94+
assertEquals("submittedAt", property1.getName());
95+
96+
BaseProperty property2 = properties.get(1);
97+
98+
assertEquals("body", property2.getName());
99+
100+
BaseObjectProperty<?> bodyProperty = (BaseObjectProperty<?>) property2;
101+
102+
List<? extends BaseProperty> bodyProperties = bodyProperty.getProperties()
103+
.orElseThrow();
104+
105+
assertEquals(8, bodyProperties.size());
106+
107+
BaseProperty bodyProperty1 = bodyProperties.getFirst();
108+
109+
assertEquals("field1", bodyProperty1.getName());
110+
assertInstanceOf(BaseProperty.BaseBooleanProperty.class, bodyProperty1);
111+
112+
BaseProperty bodyProperty2 = bodyProperties.get(1);
113+
114+
assertEquals("field2", bodyProperty2.getName());
115+
assertInstanceOf(BaseProperty.BaseDateProperty.class, bodyProperty2);
116+
117+
BaseProperty bodyProperty3 = bodyProperties.get(2);
118+
119+
assertEquals("field3", bodyProperty3.getName());
120+
assertInstanceOf(BaseProperty.BaseDateTimeProperty.class, bodyProperty3);
121+
122+
BaseProperty bodyProperty4 = bodyProperties.get(3);
123+
124+
assertEquals("field4", bodyProperty4.getName());
125+
assertInstanceOf(BaseProperty.BaseFileEntryProperty.class, bodyProperty4);
126+
127+
BaseProperty bodyProperty5 = bodyProperties.get(4);
128+
129+
assertEquals("field5", bodyProperty5.getName());
130+
assertInstanceOf(BaseProperty.BaseNumberProperty.class, bodyProperty5);
131+
132+
BaseProperty bodyProperty6 = bodyProperties.get(5);
133+
134+
assertEquals("field6", bodyProperty6.getName());
135+
assertInstanceOf(BaseProperty.BaseArrayProperty.class, bodyProperty6);
136+
137+
BaseProperty bodyProperty7 = bodyProperties.get(6);
138+
139+
assertEquals("field7", bodyProperty7.getName());
140+
assertInstanceOf(BaseProperty.BaseStringProperty.class, bodyProperty7);
141+
142+
BaseProperty bodyProperty8 = bodyProperties.get(7);
143+
144+
assertEquals("field8", bodyProperty8.getName());
145+
assertInstanceOf(BaseProperty.BaseStringProperty.class, bodyProperty8);
146+
}
147+
148+
@Test
149+
void testGetWebhookResult() {
150+
Map<String, Object> bodyContent = Map.of("key1", "value1");
151+
152+
when(mockedWebhookBody.getContent()).thenReturn(bodyContent);
153+
154+
Parameters inputParameters =
155+
MockParametersFactory.create(Map.of(IGNORE_BOTS, false, USE_WORKFLOW_TIMEZONE, false));
156+
157+
Map<String, ?> result = NewFormRequestTrigger.getWebhookResult(
158+
inputParameters, mock(Parameters.class), mockedHttpHeaders, mockedHttpParameters,
159+
mockedWebhookBody, mockedWebhookMethod, mockedWebhookEnableOutput, mockedTriggerContext);
160+
161+
assertEquals("value1", result.get("key1"));
162+
assertTrue(result.containsKey("submittedAt"));
163+
}
164+
165+
@Test
166+
void testGetWebhookResultIgnoreBots() {
167+
Map<String, Object> bodyContent = Map.of("key1", "value1");
168+
169+
when(mockedWebhookBody.getContent()).thenReturn(bodyContent);
170+
171+
Parameters inputParameters = MockParametersFactory.create(Map.of(IGNORE_BOTS, true));
172+
173+
// Test with bot user agent
174+
when(mockedHttpHeaders.firstValue("User-Agent")).thenReturn(Optional.of("Googlebot"));
175+
176+
Map<String, ?> result = NewFormRequestTrigger.getWebhookResult(
177+
inputParameters, mock(Parameters.class), mockedHttpHeaders, mockedHttpParameters,
178+
mockedWebhookBody, mockedWebhookMethod, mockedWebhookEnableOutput, mockedTriggerContext);
179+
180+
assertTrue(result.isEmpty());
181+
182+
// Test with the regular user agent
183+
when(mockedHttpHeaders.firstValue("User-Agent")).thenReturn(Optional.of("Mozilla/5.0"));
184+
185+
result = NewFormRequestTrigger.getWebhookResult(
186+
inputParameters, mock(Parameters.class), mockedHttpHeaders, mockedHttpParameters,
187+
mockedWebhookBody, mockedWebhookMethod, mockedWebhookEnableOutput, mockedTriggerContext);
188+
189+
assertEquals("value1", result.get("key1"));
190+
}
191+
192+
@Test
193+
void testGetWebhookResultUseWorkflowTimezone() {
194+
Map<String, Object> bodyContent = Map.of("key1", "value1");
195+
196+
when(mockedWebhookBody.getContent()).thenReturn(bodyContent);
197+
198+
Parameters inputParameters = MockParametersFactory.create(Map.of(USE_WORKFLOW_TIMEZONE, true));
199+
200+
Map<String, ?> result = NewFormRequestTrigger.getWebhookResult(
201+
inputParameters, mock(Parameters.class), mockedHttpHeaders, mockedHttpParameters,
202+
mockedWebhookBody, mockedWebhookMethod, mockedWebhookEnableOutput, mockedTriggerContext);
203+
204+
assertEquals("value1", result.get("key1"));
205+
assertFalse(result.containsKey("submittedAt"));
206+
}
207+
}

0 commit comments

Comments
 (0)