Skip to content

Commit 9926318

Browse files
marijahorvat171ivicac
authored andcommitted
2285 - BambooHr add triggers
1 parent 5dcfb07 commit 9926318

File tree

9 files changed

+540
-1410
lines changed

9 files changed

+540
-1410
lines changed

docs/src/content/docs/reference/components/bamboohr.md

+76-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ description: "BambooHR is a human resources software that helps HR teams manage
66
BambooHR is a human resources software that helps HR teams manage employee data, hiring, onboarding, time tracking, payroll, performance management, and more in one platform.
77

88

9-
Categories: hris
9+
Categories: Human Resources Information System
1010

1111

1212
Type: bambooHr/v1
@@ -215,3 +215,78 @@ This action does not produce any output.
215215

216216

217217

218+
## Triggers
219+
220+
221+
### Update Employee
222+
Name: updateEmployee
223+
224+
Triggers when specific employee fields are updated.
225+
226+
Type: DYNAMIC_WEBHOOK
227+
228+
229+
#### Output
230+
231+
232+
233+
Type: ARRAY
234+
235+
236+
Items Type: OBJECT
237+
238+
239+
#### Properties
240+
| Name | Type | Description |
241+
|:------------:|:------------:|:-------------------:|
242+
| firstName | STRING | |
243+
| lastName | STRING | |
244+
| employeeNumber | STRING | |
245+
246+
247+
248+
249+
250+
#### JSON Example
251+
```json
252+
{
253+
"label" : "Update Employee",
254+
"name" : "updateEmployee",
255+
"type" : "bambooHr/v1/updateEmployee"
256+
}
257+
```
258+
259+
260+
### New Employee
261+
Name: newEmployee
262+
263+
Triggers when a new employee is created.
264+
265+
Type: POLLING
266+
267+
#### Properties
268+
269+
| Name | Label | Type | Description | Required |
270+
|:---------------:|:--------------:|:------------:|:-------------------:|:--------:|
271+
| fields | null | ARRAY <details> <summary> Items </summary> [STRING] </details> | Fields you want to get from employee. See documentation for available fields. | true |
272+
273+
274+
#### Output
275+
276+
The output for this action is dynamic and may vary depending on the input parameters. To determine the exact structure of the output, you need to execute the action.
277+
278+
#### JSON Example
279+
```json
280+
{
281+
"label" : "New Employee",
282+
"name" : "newEmployee",
283+
"parameters" : {
284+
"fields" : [ "" ]
285+
},
286+
"type" : "bambooHr/v1/newEmployee"
287+
}
288+
```
289+
290+
291+
<hr />
292+

server/libs/modules/components/bamboohr/src/main/java/com/bytechef/component/bamboohr/BambooHrComponentHandler.java

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import com.bytechef.component.bamboohr.action.BambooHrUpdateEmployeeAction;
2626
import com.bytechef.component.bamboohr.action.BambooHrUpdateEmployeeFileAction;
2727
import com.bytechef.component.bamboohr.connection.BambooHrConnection;
28+
import com.bytechef.component.bamboohr.trigger.BambooHrNewEmployeeTrigger;
29+
import com.bytechef.component.bamboohr.trigger.BambooHrUpdateEmployeeTrigger;
2830
import com.bytechef.component.definition.ComponentCategory;
2931
import com.bytechef.component.definition.ComponentDefinition;
3032
import com.google.auto.service.AutoService;
@@ -48,6 +50,9 @@ public class BambooHrComponentHandler implements ComponentHandler {
4850
BambooHrUpdateEmployeeAction.ACTION_DEFINITION,
4951
BambooHrGetEmployeeAction.ACTION_DEFINITION,
5052
BambooHrUpdateEmployeeFileAction.ACTION_DEFINITION)
53+
.triggers(
54+
BambooHrUpdateEmployeeTrigger.TRIGGER_DEFINITION,
55+
BambooHrNewEmployeeTrigger.TRIGGER_DEFINITION)
5156
.clusterElements(
5257
tool(BambooHrCreateEmployeeAction.ACTION_DEFINITION),
5358
tool(BambooHrUpdateEmployeeAction.ACTION_DEFINITION),

server/libs/modules/components/bamboohr/src/main/java/com/bytechef/component/bamboohr/constant/BambooHrConstants.java

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class BambooHrConstants {
3535
public static final String LOCATION = "location";
3636
public static final String NAME = "name";
3737
public static final String SHARE_WITH_EMPLOYEE = "shareWithEmployee";
38+
public static final String LAST_TIME_CHECKED = "lastTimeChecked";
3839

3940
private BambooHrConstants() {
4041
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright 2023-present ByteChef Inc.
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.bamboohr.trigger;
18+
19+
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.FIELDS;
20+
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.ID;
21+
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.LAST_TIME_CHECKED;
22+
import static com.bytechef.component.definition.ComponentDsl.array;
23+
import static com.bytechef.component.definition.ComponentDsl.string;
24+
import static com.bytechef.component.definition.ComponentDsl.trigger;
25+
import static com.bytechef.component.definition.Context.Http.responseType;
26+
27+
import com.bytechef.component.bamboohr.util.BambooHrUtils;
28+
import com.bytechef.component.definition.ComponentDsl;
29+
import com.bytechef.component.definition.Context;
30+
import com.bytechef.component.definition.Context.Http;
31+
import com.bytechef.component.definition.OptionsDataSource;
32+
import com.bytechef.component.definition.Parameters;
33+
import com.bytechef.component.definition.TriggerContext;
34+
import com.bytechef.component.definition.TriggerDefinition;
35+
import com.bytechef.component.definition.TypeReference;
36+
import java.time.LocalDateTime;
37+
import java.time.ZoneId;
38+
import java.util.ArrayList;
39+
import java.util.List;
40+
import java.util.Map;
41+
42+
/**
43+
* @author Marija Horvat
44+
*/
45+
public class BambooHrNewEmployeeTrigger {
46+
47+
static final List<String> EMPLOYEE_LIST = new ArrayList<>();
48+
49+
public static final ComponentDsl.ModifiableTriggerDefinition TRIGGER_DEFINITION = trigger("newEmployee")
50+
.title("New Employee")
51+
.description("Triggers when a new employee is created.")
52+
.type(TriggerDefinition.TriggerType.POLLING)
53+
.properties(
54+
array(FIELDS)
55+
.description("Fields you want to get from employee. See documentation for available fields.")
56+
.items(string())
57+
.options((OptionsDataSource.TriggerOptionsFunction<String>) BambooHrUtils::getFieldOptions)
58+
.required(true))
59+
.output()
60+
.poll(BambooHrNewEmployeeTrigger::poll);
61+
62+
private BambooHrNewEmployeeTrigger() {
63+
}
64+
65+
protected static TriggerDefinition.PollOutput poll(
66+
Parameters inputParameters, Parameters connectionParameters, Parameters closureParameters,
67+
TriggerContext triggerContext) {
68+
69+
List<String> fields = inputParameters.getRequiredList(FIELDS, String.class);
70+
String queryParameter = String.join(",", fields);
71+
72+
ZoneId zoneId = ZoneId.of("GMT");
73+
74+
LocalDateTime now = LocalDateTime.now(zoneId);
75+
76+
Map<String, Object> body = triggerContext
77+
.http(http -> http.get("/employees/directory"))
78+
.header("accept", "application/json")
79+
.configuration(responseType(Context.Http.ResponseType.JSON))
80+
.execute()
81+
.getBody(new TypeReference<>() {});
82+
83+
List<Map<?, ?>> maps = new ArrayList<>();
84+
85+
if (body.get("employees") instanceof List<?> list) {
86+
if (EMPLOYEE_LIST.isEmpty()) {
87+
for (Object o : list) {
88+
if (o instanceof Map<?, ?> map) {
89+
String id = (String) map.get(ID);
90+
EMPLOYEE_LIST.add(id);
91+
}
92+
}
93+
} else {
94+
for (Object o : list) {
95+
if (o instanceof Map<?, ?> map) {
96+
String id = (String) map.get(ID);
97+
98+
if (!EMPLOYEE_LIST.contains(id)) {
99+
maps.add(
100+
triggerContext
101+
.http(http -> http.get("/employees/" + id))
102+
.queryParameter(FIELDS, queryParameter)
103+
.header("accept", "application/json")
104+
.configuration(responseType(Http.ResponseType.JSON))
105+
.execute()
106+
.getBody(new TypeReference<>() {}));
107+
}
108+
}
109+
}
110+
}
111+
}
112+
return new TriggerDefinition.PollOutput(maps, Map.of(LAST_TIME_CHECKED, now), false);
113+
}
114+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright 2023-present ByteChef Inc.
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.bamboohr.trigger;
18+
19+
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.EMPLOYEE_NUMBER;
20+
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.FIRST_NAME;
21+
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.ID;
22+
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.LAST_NAME;
23+
import static com.bytechef.component.definition.ComponentDsl.array;
24+
import static com.bytechef.component.definition.ComponentDsl.object;
25+
import static com.bytechef.component.definition.ComponentDsl.outputSchema;
26+
import static com.bytechef.component.definition.ComponentDsl.string;
27+
import static com.bytechef.component.definition.ComponentDsl.trigger;
28+
29+
import com.bytechef.component.bamboohr.util.BambooHrUtils;
30+
import com.bytechef.component.definition.ComponentDsl;
31+
import com.bytechef.component.definition.Parameters;
32+
import com.bytechef.component.definition.TriggerContext;
33+
import com.bytechef.component.definition.TriggerDefinition;
34+
import com.bytechef.component.definition.TriggerDefinition.TriggerType;
35+
import com.bytechef.component.definition.TriggerDefinition.WebhookEnableOutput;
36+
import com.bytechef.component.definition.TypeReference;
37+
import java.util.ArrayList;
38+
import java.util.HashMap;
39+
import java.util.List;
40+
import java.util.Map;
41+
42+
/**
43+
* @author Marija Horvat
44+
*/
45+
public class BambooHrUpdateEmployeeTrigger {
46+
47+
public static final ComponentDsl.ModifiableTriggerDefinition TRIGGER_DEFINITION = trigger("updateEmployee")
48+
.title("Update Employee")
49+
.description("Triggers when specific employee fields are updated.")
50+
.type(TriggerType.DYNAMIC_WEBHOOK)
51+
.properties()
52+
.output(outputSchema(
53+
array()
54+
.items(
55+
object()
56+
.properties(
57+
string(FIRST_NAME),
58+
string(LAST_NAME),
59+
string(EMPLOYEE_NUMBER)))))
60+
.webhookEnable(BambooHrUpdateEmployeeTrigger::webhookEnable)
61+
.webhookDisable(BambooHrUpdateEmployeeTrigger::webhookDisable)
62+
.webhookRequest(BambooHrUpdateEmployeeTrigger::webhookRequest);
63+
64+
private BambooHrUpdateEmployeeTrigger() {
65+
}
66+
67+
protected static WebhookEnableOutput webhookEnable(
68+
Parameters inputParameters, Parameters connectionParameters, String webhookUrl,
69+
String workflowExecutionId, TriggerContext context) {
70+
71+
return new WebhookEnableOutput(
72+
Map.of(ID,
73+
BambooHrUtils.addWebhook(webhookUrl, context)),
74+
null);
75+
}
76+
77+
protected static void webhookDisable(
78+
Parameters inputParameters, Parameters connectionParameters, Parameters outputParameters,
79+
String workflowExecutionId, TriggerContext context) {
80+
81+
BambooHrUtils.deleteWebhook(outputParameters, context);
82+
}
83+
84+
protected static Object webhookRequest(
85+
Parameters inputParameters, Parameters connectionParameters, TriggerDefinition.HttpHeaders headers,
86+
TriggerDefinition.HttpParameters parameters,
87+
TriggerDefinition.WebhookBody body, TriggerDefinition.WebhookMethod method,
88+
TriggerDefinition.WebhookEnableOutput output, TriggerContext context) {
89+
90+
List<Map<String, ?>> outputObject = new ArrayList<>();
91+
92+
if (body.getContent(new TypeReference<Map<String, ?>>() {})
93+
.get("employees") instanceof List<?> list) {
94+
for (Object o : list) {
95+
if (o instanceof Map<?, ?> map) {
96+
Map<String, Map<String, ?>> fields = (Map<String, Map<String, ?>>) map.get("fields");
97+
98+
Map<String, Object> fieldMap = new HashMap<>();
99+
100+
for (Map.Entry<String, Map<String, ?>> fieldEntry : fields.entrySet()) {
101+
String fieldName = fieldEntry.getKey();
102+
Map<String, ?> fieldValue = fieldEntry.getValue();
103+
104+
if (fieldValue.containsKey("value")) {
105+
fieldMap.put(fieldName, fieldValue.get("value"));
106+
}
107+
}
108+
outputObject.add(fieldMap);
109+
}
110+
}
111+
}
112+
return outputObject;
113+
}
114+
}

server/libs/modules/components/bamboohr/src/main/java/com/bytechef/component/bamboohr/util/BambooHrUtils.java

+32
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
package com.bytechef.component.bamboohr.util;
1818

19+
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.EMPLOYEE_NUMBER;
20+
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.FIRST_NAME;
1921
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.ID;
22+
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.LAST_NAME;
2023
import static com.bytechef.component.bamboohr.constant.BambooHrConstants.NAME;
2124
import static com.bytechef.component.definition.ComponentDsl.option;
2225
import static com.bytechef.component.definition.Context.Http.responseType;
@@ -26,6 +29,7 @@
2629
import com.bytechef.component.definition.Option;
2730
import com.bytechef.component.definition.OptionsDataSource.ActionOptionsFunction;
2831
import com.bytechef.component.definition.Parameters;
32+
import com.bytechef.component.definition.TriggerContext;
2933
import com.bytechef.component.definition.TypeReference;
3034
import java.util.ArrayList;
3135
import java.util.List;
@@ -108,6 +112,34 @@ public static List<Option<String>> getFieldOptions(
108112
return options;
109113
}
110114

115+
public static String addWebhook(
116+
String webhookUrl, TriggerContext context) {
117+
118+
Map<String, ?> body = context.http(http -> http.post("/webhooks"))
119+
.body(Context.Http.Body.of(
120+
"name", "bambooHRWebhook",
121+
"monitorFields", List.of(FIRST_NAME, LAST_NAME, EMPLOYEE_NUMBER),
122+
"postFields", Map.of(
123+
FIRST_NAME, FIRST_NAME,
124+
LAST_NAME, LAST_NAME,
125+
EMPLOYEE_NUMBER, EMPLOYEE_NUMBER),
126+
"url", webhookUrl,
127+
"format", "json"))
128+
.headers(Map.of("accept", List.of("application/json")))
129+
.configuration(Context.Http.responseType(Context.Http.ResponseType.JSON))
130+
.execute()
131+
.getBody(new TypeReference<>() {});
132+
133+
return (String) body.get(ID);
134+
}
135+
136+
public static void deleteWebhook(Parameters outputParameters, Context context) {
137+
context.http(http -> http.delete("/webhooks/" + outputParameters.getString(ID)))
138+
.headers(Map.of("accept", List.of("application/json")))
139+
.configuration(Context.Http.responseType(Context.Http.ResponseType.JSON))
140+
.execute();
141+
}
142+
111143
public static ActionOptionsFunction<String> getOptions(String targetName) {
112144
return (inputParameters, connectionParameters, arrayIndex, searchText, context) -> {
113145

0 commit comments

Comments
 (0)