From afa839fd07bd55db4530f6d1112d3064cf792060 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Fri, 14 Jun 2024 15:02:00 -0300 Subject: [PATCH 1/6] okta init --- .../okta/actions/create-user/create-user.mjs | 34 ++++++ components/okta/actions/get-user/get-user.mjs | 19 ++++ .../okta/actions/update-user/update-user.mjs | 20 ++++ components/okta/okta.app.mjs | 101 +++++++++++++++++- components/okta/package.json | 2 +- .../watch-new-events/watch-new-events.mjs | 62 +++++++++++ 6 files changed, 232 insertions(+), 6 deletions(-) create mode 100644 components/okta/actions/create-user/create-user.mjs create mode 100644 components/okta/actions/get-user/get-user.mjs create mode 100644 components/okta/actions/update-user/update-user.mjs create mode 100644 components/okta/sources/watch-new-events/watch-new-events.mjs diff --git a/components/okta/actions/create-user/create-user.mjs b/components/okta/actions/create-user/create-user.mjs new file mode 100644 index 0000000000000..9767c6f56d6d4 --- /dev/null +++ b/components/okta/actions/create-user/create-user.mjs @@ -0,0 +1,34 @@ +import okta from "../../okta.app.mjs"; + +export default { + key: "okta-create-user", + name: "Create User", + description: "Creates a new user in the Okta system. The user will receive an email with the account creation prompt.", + version: "0.0.{{ts}}", + type: "action", + props: { + okta, + firstName: okta.propDefinitions.firstName, + lastName: okta.propDefinitions.lastName, + email: okta.propDefinitions.email, + login: { + ...okta.propDefinitions.login, + optional: true, + }, + mobilePhone: { + ...okta.propDefinitions.mobilePhone, + optional: true, + }, + }, + async run({ $ }) { + const response = await this.okta.createUser({ + firstName: this.firstName, + lastName: this.lastName, + email: this.email, + login: this.login, + mobilePhone: this.mobilePhone, + }); + $.export("$summary", `Successfully created user ${this.firstName} ${this.lastName}`); + return response; + }, +}; diff --git a/components/okta/actions/get-user/get-user.mjs b/components/okta/actions/get-user/get-user.mjs new file mode 100644 index 0000000000000..f883a8e489b6c --- /dev/null +++ b/components/okta/actions/get-user/get-user.mjs @@ -0,0 +1,19 @@ +import okta from "../../okta.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "okta-get-user", + name: "Get User", + description: "Fetches the information of a specific user from the Okta system. [See the documentation](https://developer.okta.com/docs/reference/api/users/#get-user)", + version: "0.0.{{ts}}", + type: "action", + props: { + okta, + userId: okta.propDefinitions.userId, + }, + async run({ $ }) { + const response = await this.okta.fetchUser(this.userId); + $.export("$summary", `Successfully fetched user details for user ID ${this.userId}`); + return response; + }, +}; diff --git a/components/okta/actions/update-user/update-user.mjs b/components/okta/actions/update-user/update-user.mjs new file mode 100644 index 0000000000000..4e9b7b71891b6 --- /dev/null +++ b/components/okta/actions/update-user/update-user.mjs @@ -0,0 +1,20 @@ +import okta from "../../okta.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "okta-update-user", + name: "Update User", + description: "Updates the profile and/or credentials of a specific user in the Okta system. The mandatory props are 'user ID' and the details that need to be updated.", + version: "0.0.${ts}", + type: "action", + props: { + okta, + userId: okta.propDefinitions.userId, + updateDetails: okta.propDefinitions.updateDetails, + }, + async run({ $ }) { + const response = await this.okta.updateUser(this.userId, this.updateDetails); + $.export("$summary", `Successfully updated user with ID ${this.userId}`); + return response; + }, +}; diff --git a/components/okta/okta.app.mjs b/components/okta/okta.app.mjs index c1db43d3bf9f5..3a0ae5414b01c 100644 --- a/components/okta/okta.app.mjs +++ b/components/okta/okta.app.mjs @@ -1,11 +1,102 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "okta", - propDefinitions: {}, + propDefinitions: { + userId: { + type: "string", + label: "User ID", + description: "The unique identifier of the user.", + }, + firstName: { + type: "string", + label: "First Name", + description: "The first name of the user.", + }, + lastName: { + type: "string", + label: "Last Name", + description: "The last name of the user.", + }, + email: { + type: "string", + label: "Email", + description: "The email address of the user.", + }, + login: { + type: "string", + label: "Login", + description: "The login for the user (optional).", + optional: true, + }, + mobilePhone: { + type: "string", + label: "Mobile Phone", + description: "The mobile phone number of the user (optional).", + optional: true, + }, + updateDetails: { + type: "object", + label: "Update Details", + description: "The details to update for the user.", + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://your-domain.okta.com/api/v1"; + }, + async _makeRequest(opts = {}) { + const { + $ = this, method = "GET", path, headers, ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + method, + url: this._baseUrl() + path, + headers: { + ...headers, + "Authorization": `SSWS ${this.$auth.api_token}`, + "Content-Type": "application/json", + "Accept": "application/json", + }, + }); + }, + async createUser({ + firstName, lastName, email, login, mobilePhone, + }) { + const user = { + profile: { + firstName, + lastName, + email, + login: login || email, + mobilePhone, + }, + credentials: { + password: { + value: "TempP@ssw0rd!", + }, + }, + }; + return this._makeRequest({ + method: "POST", + path: "/users?activate=true", + data: user, + }); + }, + async fetchUser(userId) { + return this._makeRequest({ + method: "GET", + path: `/users/${userId}`, + }); + }, + async updateUser(userId, updateDetails) { + return this._makeRequest({ + method: "POST", + path: `/users/${userId}`, + data: updateDetails, + }); }, }, -}; \ No newline at end of file +}; diff --git a/components/okta/package.json b/components/okta/package.json index 5b9f81e07e7ee..fed6391578358 100644 --- a/components/okta/package.json +++ b/components/okta/package.json @@ -12,4 +12,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/components/okta/sources/watch-new-events/watch-new-events.mjs b/components/okta/sources/watch-new-events/watch-new-events.mjs new file mode 100644 index 0000000000000..b7005e6f77333 --- /dev/null +++ b/components/okta/sources/watch-new-events/watch-new-events.mjs @@ -0,0 +1,62 @@ +import { axios } from "@pipedream/platform"; +import okta from "../../okta.app.mjs"; + +export default { + key: "okta-watch-new-events", + name: "Watch New Events", + description: "Emit new event when the system observes a new event. [See the documentation](https://developer.okta.com/docs/api/)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + okta, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: 300, // every 5 minutes + }, + }, + }, + hooks: { + async deploy() { + // Fetch the last 50 events to avoid duplicates on initial run + const since = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(); // 1 day ago + const events = await this.okta._makeRequest({ + path: `/logs?since=${since}&limit=50`, + }); + events.forEach((event) => { + this.$emit(event, { + id: event.uuid, + summary: `New event: ${event.eventType}`, + ts: Date.parse(event.published), + }); + }); + // Update the last event time to the most recent event's published time + if (events.length > 0) { + const latestEventTime = events[0].published; + this.db.set("lastEventTime", latestEventTime); + } + }, + }, + async run() { + const lastEventTime = this.db.get("lastEventTime") || new Date().toISOString(); + const events = await this.okta._makeRequest({ + path: `/logs?since=${lastEventTime}&limit=100`, + }); + + events.forEach((event) => { + this.$emit(event, { + id: event.uuid, + summary: `New event: ${event.eventType}`, + ts: Date.parse(event.published), + }); + }); + + // Update the last event time to the most recent event's published time + if (events.length > 0) { + const mostRecentEvent = events[0].published; + this.db.set("lastEventTime", mostRecentEvent); + } + }, +}; From 69d0a3d4f37b2cb5145ccc742478e4742e24cbd8 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 17 Jun 2024 13:09:59 -0300 Subject: [PATCH 2/6] [Components] okta #12420 Polling Sources - Watch New Events Actions - Create User - Get User - Update User --- .../okta/actions/create-user/create-user.mjs | 94 +++++++-- components/okta/actions/get-user/get-user.mjs | 17 +- .../okta/actions/update-user/update-user.mjs | 87 +++++++- components/okta/common/constants.mjs | 1 + components/okta/common/utils.mjs | 24 +++ components/okta/okta.app.mjs | 199 ++++++++++++++---- components/okta/package.json | 6 +- .../sources/watch-new-events/test-event.mjs | 118 +++++++++++ .../watch-new-events/watch-new-events.mjs | 85 ++++---- 9 files changed, 516 insertions(+), 115 deletions(-) create mode 100644 components/okta/common/constants.mjs create mode 100644 components/okta/common/utils.mjs create mode 100644 components/okta/sources/watch-new-events/test-event.mjs diff --git a/components/okta/actions/create-user/create-user.mjs b/components/okta/actions/create-user/create-user.mjs index 9767c6f56d6d4..7148e459fb3e4 100644 --- a/components/okta/actions/create-user/create-user.mjs +++ b/components/okta/actions/create-user/create-user.mjs @@ -1,34 +1,94 @@ +import { ConfigurationError } from "@pipedream/platform"; +// import { parseObject } from "../../common/utils.mjs"; import okta from "../../okta.app.mjs"; export default { key: "okta-create-user", name: "Create User", - description: "Creates a new user in the Okta system. The user will receive an email with the account creation prompt.", - version: "0.0.{{ts}}", + description: "Creates a new user in the Okta system. [See the documentation](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/User/#tag/User/operation/createUser)", + version: "0.0.1", type: "action", props: { okta, - firstName: okta.propDefinitions.firstName, - lastName: okta.propDefinitions.lastName, - email: okta.propDefinitions.email, - login: { - ...okta.propDefinitions.login, + activate: { + type: "boolean", + label: "Activate", + description: "Executes activation lifecycle operation when creating the user. Defaults to true.", optional: true, }, + firstName: { + propDefinition: [ + okta, + "firstName", + ], + }, + lastName: { + propDefinition: [ + okta, + "lastName", + ], + }, + email: { + propDefinition: [ + okta, + "email", + ], + }, + login: { + propDefinition: [ + okta, + "login", + ], + }, mobilePhone: { - ...okta.propDefinitions.mobilePhone, + propDefinition: [ + okta, + "mobilePhone", + ], + optional: true, + }, + typeId: { + propDefinition: [ + okta, + "typeId", + ], optional: true, }, }, async run({ $ }) { - const response = await this.okta.createUser({ - firstName: this.firstName, - lastName: this.lastName, - email: this.email, - login: this.login, - mobilePhone: this.mobilePhone, - }); - $.export("$summary", `Successfully created user ${this.firstName} ${this.lastName}`); - return response; + try { + const { + okta, + activate, + typeId, + ...profile + } = this; + + const data = { + profile, + }; + + if (typeId) { + data.type = { + id: this.typeId, + }; + } + + const response = await okta.createUser({ + $, + data, + params: { + activate, + }, + }); + + $.export("$summary", `Successfully created user with ID ${response.id}`); + return response; + } catch ({ message }) { + const messageError = JSON.parse(message); + throw new ConfigurationError(messageError.errorCauses.length + ? messageError.errorCauses[0].errorSummary + : messageError.errorSummary); + } }, }; diff --git a/components/okta/actions/get-user/get-user.mjs b/components/okta/actions/get-user/get-user.mjs index f883a8e489b6c..60c4980185f6d 100644 --- a/components/okta/actions/get-user/get-user.mjs +++ b/components/okta/actions/get-user/get-user.mjs @@ -1,18 +1,25 @@ import okta from "../../okta.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "okta-get-user", name: "Get User", - description: "Fetches the information of a specific user from the Okta system. [See the documentation](https://developer.okta.com/docs/reference/api/users/#get-user)", - version: "0.0.{{ts}}", + description: "Fetches the information of a specific user from the Okta system. [See the documentation](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/User/#tag/User/operation/getUser)", + version: "0.0.1", type: "action", props: { okta, - userId: okta.propDefinitions.userId, + userId: { + propDefinition: [ + okta, + "userId", + ], + }, }, async run({ $ }) { - const response = await this.okta.fetchUser(this.userId); + const response = await this.okta.getUser({ + $, + userId: this.userId, + }); $.export("$summary", `Successfully fetched user details for user ID ${this.userId}`); return response; }, diff --git a/components/okta/actions/update-user/update-user.mjs b/components/okta/actions/update-user/update-user.mjs index 4e9b7b71891b6..d2a111198e51f 100644 --- a/components/okta/actions/update-user/update-user.mjs +++ b/components/okta/actions/update-user/update-user.mjs @@ -1,20 +1,93 @@ import okta from "../../okta.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "okta-update-user", name: "Update User", - description: "Updates the profile and/or credentials of a specific user in the Okta system. The mandatory props are 'user ID' and the details that need to be updated.", - version: "0.0.${ts}", + description: "Updates the profile of a specific user in the Okta system. [See the documentation](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/User/#tag/User/operation/updateUser)", + version: "0.0.1", type: "action", props: { okta, - userId: okta.propDefinitions.userId, - updateDetails: okta.propDefinitions.updateDetails, + userId: { + propDefinition: [ + okta, + "userId", + ], + }, + firstName: { + propDefinition: [ + okta, + "firstName", + ], + optional: true, + }, + lastName: { + propDefinition: [ + okta, + "lastName", + ], + optional: true, + }, + email: { + propDefinition: [ + okta, + "email", + ], + optional: true, + }, + login: { + propDefinition: [ + okta, + "login", + ], + optional: true, + }, + mobilePhone: { + propDefinition: [ + okta, + "mobilePhone", + ], + optional: true, + }, + typeId: { + propDefinition: [ + okta, + "typeId", + ], + optional: true, + }, }, async run({ $ }) { - const response = await this.okta.updateUser(this.userId, this.updateDetails); - $.export("$summary", `Successfully updated user with ID ${this.userId}`); + const { + okta, + userId, + typeId, + ...profile + } = this; + + const { profile: userProfile } = await okta.getUser({ + userId, + }); + + const response = await okta.updateUser({ + $, + userId, + data: { + profile: { + ...userProfile, + ...profile, + }, + ...(typeId + ? { + type: { + id: this.typeId, + }, + } : + {}), + }, + }); + + $.export("$summary", `Successfully updated user with ID ${userId}`); return response; }, }; diff --git a/components/okta/common/constants.mjs b/components/okta/common/constants.mjs new file mode 100644 index 0000000000000..e67b995b66aa4 --- /dev/null +++ b/components/okta/common/constants.mjs @@ -0,0 +1 @@ +export const LIMIT = 1000; diff --git a/components/okta/common/utils.mjs b/components/okta/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/okta/common/utils.mjs @@ -0,0 +1,24 @@ +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; diff --git a/components/okta/okta.app.mjs b/components/okta/okta.app.mjs index 3a0ae5414b01c..e45b6ee93ba64 100644 --- a/components/okta/okta.app.mjs +++ b/components/okta/okta.app.mjs @@ -1,13 +1,82 @@ import { axios } from "@pipedream/platform"; +import { LIMIT } from "./common/constants.mjs"; export default { type: "app", app: "okta", propDefinitions: { + typeId: { + type: "string", + label: "Type Id", + description: "The ID of the user type. Add this value if you want to create a user with a non-default user type. The user type determines which schema applies to that user. After a user has been created, the user can only be assigned a different user type by an administrator through a full replacement (PUT) operation.", + async options() { + const data = await this.listUserTypes(); + + return data.map(({ + id: value, displayName: label, + }) => ({ + label, + value, + })); + }, + }, + groupIds: { + type: "string[]", + label: "Group Ids", + description: "An array of group Ids.", + async options({ prevContext = {} }) { + let after = ""; + if (prevContext.nextToken) { + after = prevContext.nextToken; + } + const data = await this.listGroups({ + params: { + limit: LIMIT, + after, + }, + }); + + return { + options: data.map(({ + id: value, profile: { name: label }, + }) => ({ + label, + value, + })), + context: { + nextToken: data[data.length - 1].id, + }, + }; + }, + }, userId: { type: "string", label: "User ID", description: "The unique identifier of the user.", + async options({ prevContext }) { + let after = ""; + if (prevContext.nextToken) { + after = prevContext.nextToken; + } + const data = await this.listUsers({ + params: { + limit: LIMIT, + after, + }, + }); + + return { + options: data.map(({ + id: value, profile: { email: label }, + }) => ({ + label, + value, + })), + context: { + nextToken: data[data.length - 1].id, + }, + }; + }, }, firstName: { type: "string", @@ -27,76 +96,114 @@ export default { login: { type: "string", label: "Login", - description: "The login for the user (optional).", - optional: true, + description: "The login for the user.", }, mobilePhone: { type: "string", label: "Mobile Phone", - description: "The mobile phone number of the user (optional).", - optional: true, - }, - updateDetails: { - type: "object", - label: "Update Details", - description: "The details to update for the user.", + description: "The mobile phone number of the user.", }, }, methods: { _baseUrl() { - return "https://your-domain.okta.com/api/v1"; + return `https://${this.$auth.subdomain}.okta.com/api/v1`; + }, + _headers() { + return { + "Authorization": `SSWS ${this.$auth.api_token}`, + "Content-Type": "application/json", + "Accept": "application/json; okta-version=1.0.0", + }; }, - async _makeRequest(opts = {}) { - const { - $ = this, method = "GET", path, headers, ...otherOpts - } = opts; + _makeRequest({ + $ = this, path, ...opts + }) { return axios($, { - ...otherOpts, - method, url: this._baseUrl() + path, - headers: { - ...headers, - "Authorization": `SSWS ${this.$auth.api_token}`, - "Content-Type": "application/json", - "Accept": "application/json", - }, + headers: this._headers(), + ...opts, }); }, - async createUser({ - firstName, lastName, email, login, mobilePhone, + getUser({ + userId, ...opts }) { - const user = { - profile: { - firstName, - lastName, - email, - login: login || email, - mobilePhone, - }, - credentials: { - password: { - value: "TempP@ssw0rd!", - }, - }, - }; return this._makeRequest({ - method: "POST", - path: "/users?activate=true", - data: user, + path: `/users/${userId}`, + ...opts, }); }, - async fetchUser(userId) { + listUserTypes() { return this._makeRequest({ - method: "GET", - path: `/users/${userId}`, + path: "/meta/types/user", + }); + }, + listGroups(opts = {}) { + return this._makeRequest({ + path: "/groups", + ...opts, + }); + }, + listLogs(opts = {}) { + return this._makeRequest({ + path: "/logs", + ...opts, }); }, - async updateUser(userId, updateDetails) { + listUsers(opts = {}) { + return this._makeRequest({ + path: "/users", + ...opts, + }); + }, + createUser(opts = {}) { return this._makeRequest({ method: "POST", + path: "/users", + ...opts, + }); + }, + updateUser({ + userId, ...opts + }) { + return this._makeRequest({ + method: "PUT", path: `/users/${userId}`, - data: updateDetails, + ...opts, }); }, + async *paginate({ + fn, params = {}, maxResults = null, ...opts + }) { + let hasMore = false; + let count = 0; + let after = null; + + do { + params.after = after; + const { + headers: { link }, data, + } = await fn({ + returnFullResponse: true, + params, + ...opts, + }); + + for (const d of data) { + yield d; + + if (maxResults && ++count === maxResults) { + return count; + } + } + + const nextToken = link.match(/after=(\w+)/); + if (nextToken) { + after = nextToken[1]; + } + + hasMore = nextToken; + + } while (hasMore); + }, }, }; diff --git a/components/okta/package.json b/components/okta/package.json index fed6391578358..cfa8023ced5fe 100644 --- a/components/okta/package.json +++ b/components/okta/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/okta", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Okta Components", "main": "okta.app.mjs", "keywords": [ @@ -11,5 +11,9 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^2.0.0" } } + diff --git a/components/okta/sources/watch-new-events/test-event.mjs b/components/okta/sources/watch-new-events/test-event.mjs new file mode 100644 index 0000000000000..fab9bba1a44d6 --- /dev/null +++ b/components/okta/sources/watch-new-events/test-event.mjs @@ -0,0 +1,118 @@ +export default { + "actor": { + "alternateId": "string", + "detailEntry": { + "property1": {}, + "property2": {} + }, + "displayName": "string", + "id": "string", + "type": "string" + }, + "authenticationContext": { + "authenticationProvider": "ACTIVE_DIRECTORY", + "authenticationStep": 0, + "credentialProvider": "DUO", + "credentialType": "ASSERTION", + "externalSessionId": "string", + "interface": "string", + "issuer": { + "id": "string", + "type": "string" + } + }, + "client": { + "device": "string", + "geographicalContext": { + "city": "string", + "country": "string", + "geolocation": { + "lat": 0, + "lon": 0 + }, + "postalCode": "string", + "state": "string" + }, + "id": "string", + "ipAddress": "string", + "userAgent": { + "browser": "string", + "os": "string", + "rawUserAgent": "string" + }, + "zone": "string" + }, + "debugContext": { + "debugData": { + "property1": {}, + "property2": {} + } + }, + "displayMessage": "string", + "eventType": "string", + "legacyEventType": "string", + "outcome": { + "reason": "string", + "result": "string" + }, + "published": "2019-08-24T14:15:22Z", + "request": { + "ipChain": [ + { + "geographicalContext": { + "city": "string", + "country": "string", + "geolocation": { + "lat": 0, + "lon": 0 + }, + "postalCode": "string", + "state": "string" + }, + "ip": "string", + "source": "string", + "version": "string" + } + ] + }, + "securityContext": { + "asNumber": 0, + "asOrg": "string", + "domain": "string", + "isp": "string", + "isProxy": true + }, + "severity": "DEBUG", + "target": [ + { + "alternateId": "string", + "changeDetails": { + "from": { + "property1": {}, + "property2": {} + }, + "to": { + "property1": {}, + "property2": {} + } + }, + "detailEntry": { + "property1": {}, + "property2": {} + }, + "displayName": "string", + "id": "string", + "type": "string" + } + ], + "transaction": { + "detail": { + "property1": {}, + "property2": {} + }, + "id": "string", + "type": "string" + }, + "uuid": "string", + "version": "string" +} \ No newline at end of file diff --git a/components/okta/sources/watch-new-events/watch-new-events.mjs b/components/okta/sources/watch-new-events/watch-new-events.mjs index b7005e6f77333..7875431b722eb 100644 --- a/components/okta/sources/watch-new-events/watch-new-events.mjs +++ b/components/okta/sources/watch-new-events/watch-new-events.mjs @@ -1,10 +1,11 @@ -import { axios } from "@pipedream/platform"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; import okta from "../../okta.app.mjs"; +import sampleEmit from "./test-event.mjs"; export default { key: "okta-watch-new-events", - name: "Watch New Events", - description: "Emit new event when the system observes a new event. [See the documentation](https://developer.okta.com/docs/api/)", + name: "New Okta Event", + description: "Emit new event when the system observes a new event.", version: "0.0.1", type: "source", dedupe: "unique", @@ -14,49 +15,55 @@ export default { timer: { type: "$.interface.timer", default: { - intervalSeconds: 300, // every 5 minutes + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, }, }, }, - hooks: { - async deploy() { - // Fetch the last 50 events to avoid duplicates on initial run - const since = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(); // 1 day ago - const events = await this.okta._makeRequest({ - path: `/logs?since=${since}&limit=50`, - }); - events.forEach((event) => { - this.$emit(event, { - id: event.uuid, - summary: `New event: ${event.eventType}`, - ts: Date.parse(event.published), - }); + methods: { + _getLastDate() { + return this.db.get("lastDate") || "1970-01-01T00:00:00Z"; + }, + _setLastDate(created) { + this.db.set("lastDate", created); + }, + generateMeta(event) { + return { + id: event.uuid, + summary: `New Okta Event: ${event.eventType}`, + ts: event.published, + }; + }, + async startEvent(maxResults = 0) { + const lastDate = this._getLastDate(); + const response = this.okta.paginate({ + fn: this.okta.listLogs, + maxResults, + params: { + since: lastDate, + sortOrder: "DESCENDING", + }, }); - // Update the last event time to the most recent event's published time - if (events.length > 0) { - const latestEventTime = events[0].published; - this.db.set("lastEventTime", latestEventTime); + + let responseArray = []; + + for await (const item of response) { + responseArray.push(item); + } + + if (responseArray.length) this._setLastDate(responseArray[0].published); + + for (const event of responseArray.reverse()) { + this.$emit(event, this.generateMeta(event)); } }, }, + hooks: { + async deploy() { + await this.startEvent(25); + }, + }, async run() { - const lastEventTime = this.db.get("lastEventTime") || new Date().toISOString(); - const events = await this.okta._makeRequest({ - path: `/logs?since=${lastEventTime}&limit=100`, - }); - - events.forEach((event) => { - this.$emit(event, { - id: event.uuid, - summary: `New event: ${event.eventType}`, - ts: Date.parse(event.published), - }); - }); - - // Update the last event time to the most recent event's published time - if (events.length > 0) { - const mostRecentEvent = events[0].published; - this.db.set("lastEventTime", mostRecentEvent); - } + await this.startEvent(); }, + sampleEmit, }; From 4457a87fb17576d775adf4ec77f24b25d6c66f6d Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 17 Jun 2024 13:11:09 -0300 Subject: [PATCH 3/6] pnpm update --- pnpm-lock.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 57fb5205736a3..d6e4b5fb44453 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5931,7 +5931,10 @@ importers: specifiers: {} components/okta: - specifiers: {} + specifiers: + '@pipedream/platform': ^2.0.0 + dependencies: + '@pipedream/platform': 2.0.0 components/omise: specifiers: From 1d7c732bcb69637aa1834a4c3dd4fd02a836646e Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 17 Jun 2024 16:40:25 -0300 Subject: [PATCH 4/6] Update components/okta/actions/create-user/create-user.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- components/okta/actions/create-user/create-user.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/okta/actions/create-user/create-user.mjs b/components/okta/actions/create-user/create-user.mjs index 7148e459fb3e4..6371cab5ef8a2 100644 --- a/components/okta/actions/create-user/create-user.mjs +++ b/components/okta/actions/create-user/create-user.mjs @@ -1,5 +1,4 @@ import { ConfigurationError } from "@pipedream/platform"; -// import { parseObject } from "../../common/utils.mjs"; import okta from "../../okta.app.mjs"; export default { From ecb2f92446575a37b0d36a3144b985c32b9311c3 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 17 Jun 2024 16:40:46 -0300 Subject: [PATCH 5/6] Update components/okta/sources/watch-new-events/watch-new-events.mjs Co-authored-by: michelle0927 --- components/okta/sources/watch-new-events/watch-new-events.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/okta/sources/watch-new-events/watch-new-events.mjs b/components/okta/sources/watch-new-events/watch-new-events.mjs index 7875431b722eb..9c49dff84aa63 100644 --- a/components/okta/sources/watch-new-events/watch-new-events.mjs +++ b/components/okta/sources/watch-new-events/watch-new-events.mjs @@ -30,7 +30,7 @@ export default { return { id: event.uuid, summary: `New Okta Event: ${event.eventType}`, - ts: event.published, + ts: Date.parse(event.published), }; }, async startEvent(maxResults = 0) { From c1d6fd60d071bf98e8e001c9498f681940655cf4 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 17 Jun 2024 16:42:19 -0300 Subject: [PATCH 6/6] remove utils.mjs --- components/okta/common/utils.mjs | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 components/okta/common/utils.mjs diff --git a/components/okta/common/utils.mjs b/components/okta/common/utils.mjs deleted file mode 100644 index dcc9cc61f6f41..0000000000000 --- a/components/okta/common/utils.mjs +++ /dev/null @@ -1,24 +0,0 @@ -export const parseObject = (obj) => { - if (!obj) return undefined; - - if (Array.isArray(obj)) { - return obj.map((item) => { - if (typeof item === "string") { - try { - return JSON.parse(item); - } catch (e) { - return item; - } - } - return item; - }); - } - if (typeof obj === "string") { - try { - return JSON.parse(obj); - } catch (e) { - return obj; - } - } - return obj; -};