From 6488ad4e7672a4d3af1f2426c1a1fb27c9e11093 Mon Sep 17 00:00:00 2001
From: Luan Cazarine <luanhc@gmail.com>
Date: Thu, 13 Feb 2025 13:58:30 -0300
Subject: [PATCH 1/3] onelogin init

---
 .../actions/create-user/create-user.mjs       | 232 +++++++++++
 .../revoke-user-sessions.mjs                  |  23 ++
 .../actions/update-user/update-user.mjs       | 224 +++++++++++
 components/onelogin/onelogin.app.mjs          | 368 +++++++++++++++++-
 components/onelogin/package.json              |   2 +-
 .../new-directory-sync-event.mjs              | 104 +++++
 .../new-login-attempt/new-login-attempt.mjs   | 124 ++++++
 .../onelogin/sources/new-user/new-user.mjs    | 102 +++++
 8 files changed, 1176 insertions(+), 3 deletions(-)
 create mode 100644 components/onelogin/actions/create-user/create-user.mjs
 create mode 100644 components/onelogin/actions/revoke-user-sessions/revoke-user-sessions.mjs
 create mode 100644 components/onelogin/actions/update-user/update-user.mjs
 create mode 100644 components/onelogin/sources/new-directory-sync-event/new-directory-sync-event.mjs
 create mode 100644 components/onelogin/sources/new-login-attempt/new-login-attempt.mjs
 create mode 100644 components/onelogin/sources/new-user/new-user.mjs

diff --git a/components/onelogin/actions/create-user/create-user.mjs b/components/onelogin/actions/create-user/create-user.mjs
new file mode 100644
index 0000000000000..7f3a52a1d4a8e
--- /dev/null
+++ b/components/onelogin/actions/create-user/create-user.mjs
@@ -0,0 +1,232 @@
+import onelogin from "../../onelogin.app.mjs";
+import { axios } from "@pipedream/platform";
+
+export default {
+  key: "onelogin-create-user",
+  name: "Create User",
+  description: "Creates a new user in OneLogin. [See the documentation](https://developers.onelogin.com/api-docs/1/users/create-user)",
+  version: "0.0.{{ts}}",
+  type: "action",
+  props: {
+    onelogin,
+    firstname: {
+      propDefinition: [
+        onelogin,
+        "firstname",
+      ],
+    },
+    lastname: {
+      propDefinition: [
+        onelogin,
+        "lastname",
+      ],
+    },
+    email: {
+      propDefinition: [
+        onelogin,
+        "email",
+      ],
+      optional: true,
+    },
+    username: {
+      propDefinition: [
+        onelogin,
+        "username",
+      ],
+      optional: true,
+    },
+    company: {
+      propDefinition: [
+        onelogin,
+        "company",
+      ],
+      optional: true,
+    },
+    department: {
+      propDefinition: [
+        onelogin,
+        "department",
+      ],
+      optional: true,
+    },
+    directoryId: {
+      propDefinition: [
+        onelogin,
+        "directoryId",
+      ],
+      optional: true,
+    },
+    distinguishedName: {
+      propDefinition: [
+        onelogin,
+        "distinguishedName",
+      ],
+      optional: true,
+    },
+    externalId: {
+      propDefinition: [
+        onelogin,
+        "externalId",
+      ],
+      optional: true,
+    },
+    groupId: {
+      propDefinition: [
+        onelogin,
+        "groupId",
+      ],
+      optional: true,
+    },
+    invalidLoginAttempts: {
+      propDefinition: [
+        onelogin,
+        "invalidLoginAttempts",
+      ],
+      optional: true,
+    },
+    localeCode: {
+      propDefinition: [
+        onelogin,
+        "localeCode",
+      ],
+      optional: true,
+    },
+    memberOf: {
+      propDefinition: [
+        onelogin,
+        "memberOf",
+      ],
+      optional: true,
+    },
+    openidName: {
+      propDefinition: [
+        onelogin,
+        "openidName",
+      ],
+      optional: true,
+    },
+    phone: {
+      propDefinition: [
+        onelogin,
+        "phone",
+      ],
+      optional: true,
+    },
+    samaccountname: {
+      propDefinition: [
+        onelogin,
+        "samaccountname",
+      ],
+      optional: true,
+    },
+    title: {
+      propDefinition: [
+        onelogin,
+        "title",
+      ],
+      optional: true,
+    },
+    customAttributes: {
+      propDefinition: [
+        onelogin,
+        "customAttributes",
+      ],
+      optional: true,
+    },
+  },
+  async run({ $ }) {
+    if (!this.email && !this.username) {
+      throw new Error("Either email or username must be provided.");
+    }
+
+    const userData = {
+      firstname: this.firstname,
+      lastname: this.lastname,
+      ...(this.email
+        ? {
+          email: this.email,
+        }
+        : {}),
+      ...(this.username
+        ? {
+          username: this.username,
+        }
+        : {}),
+      ...(this.company != null
+        ? {
+          company: this.company,
+        }
+        : {}),
+      ...(this.department != null
+        ? {
+          department: this.department,
+        }
+        : {}),
+      ...(this.directoryId != null
+        ? {
+          directory_id: this.directoryId,
+        }
+        : {}),
+      ...(this.distinguishedName != null
+        ? {
+          distinguished_name: this.distinguishedName,
+        }
+        : {}),
+      ...(this.externalId != null
+        ? {
+          external_id: this.externalId,
+        }
+        : {}),
+      ...(this.groupId != null
+        ? {
+          group_id: parseInt(this.groupId, 10),
+        }
+        : {}),
+      ...(this.invalidLoginAttempts != null
+        ? {
+          invalid_login_attempts: this.invalidLoginAttempts,
+        }
+        : {}),
+      ...(this.localeCode != null
+        ? {
+          locale_code: this.localeCode,
+        }
+        : {}),
+      ...(this.memberOf != null
+        ? {
+          member_of: this.memberOf,
+        }
+        : {}),
+      ...(this.openidName != null
+        ? {
+          openid_name: this.openidName,
+        }
+        : {}),
+      ...(this.phone != null
+        ? {
+          phone: this.phone,
+        }
+        : {}),
+      ...(this.samaccountname != null
+        ? {
+          samaccountname: this.samaccountname,
+        }
+        : {}),
+      ...(this.title != null
+        ? {
+          title: this.title,
+        }
+        : {}),
+      ...(this.customAttributes != null
+        ? {
+          custom_attributes: this.customAttributes,
+        }
+        : {}),
+    };
+
+    const response = await this.onelogin.createUser(userData);
+
+    $.export("$summary", `Created user ${response.username} with ID ${response.id}`);
+    return response;
+  },
+};
diff --git a/components/onelogin/actions/revoke-user-sessions/revoke-user-sessions.mjs b/components/onelogin/actions/revoke-user-sessions/revoke-user-sessions.mjs
new file mode 100644
index 0000000000000..0f71ad5fc9272
--- /dev/null
+++ b/components/onelogin/actions/revoke-user-sessions/revoke-user-sessions.mjs
@@ -0,0 +1,23 @@
+import onelogin from "../../onelogin.app.mjs";
+
+export default {
+  key: "onelogin-revoke-user-sessions",
+  name: "Revoke User Sessions",
+  description: "Revokes all active sessions for a specified user in OneLogin. [See the documentation]()",
+  version: "0.0.{{ts}}",
+  type: "action",
+  props: {
+    onelogin,
+    revokeUserId: {
+      propDefinition: [
+        onelogin,
+        "revokeUserId",
+      ],
+    },
+  },
+  async run({ $ }) {
+    const response = await this.onelogin.revokeUserSessions(this.revokeUserId);
+    $.export("$summary", `Successfully revoked sessions for user ID ${this.revokeUserId}`);
+    return response;
+  },
+};
diff --git a/components/onelogin/actions/update-user/update-user.mjs b/components/onelogin/actions/update-user/update-user.mjs
new file mode 100644
index 0000000000000..bd86bf0a781b1
--- /dev/null
+++ b/components/onelogin/actions/update-user/update-user.mjs
@@ -0,0 +1,224 @@
+import onelogin from "../../onelogin.app.mjs";
+import { axios } from "@pipedream/platform";
+
+export default {
+  key: "onelogin-update-user",
+  name: "Update User",
+  description: "Updates an existing user's details in OneLogin. [See the documentation]()",
+  version: "0.0.{{ts}}",
+  type: "action",
+  props: {
+    onelogin,
+    updateUserId: {
+      propDefinition: [
+        onelogin,
+        "updateUserId",
+      ],
+    },
+    firstname: {
+      propDefinition: [
+        onelogin,
+        "firstname",
+      ],
+      optional: true,
+    },
+    lastname: {
+      propDefinition: [
+        onelogin,
+        "lastname",
+      ],
+      optional: true,
+    },
+    email: {
+      propDefinition: [
+        onelogin,
+        "email",
+      ],
+      optional: true,
+    },
+    username: {
+      propDefinition: [
+        onelogin,
+        "username",
+      ],
+      optional: true,
+    },
+    company: {
+      propDefinition: [
+        onelogin,
+        "company",
+      ],
+      optional: true,
+    },
+    department: {
+      propDefinition: [
+        onelogin,
+        "department",
+      ],
+      optional: true,
+    },
+    directoryId: {
+      propDefinition: [
+        onelogin,
+        "directoryId",
+      ],
+      optional: true,
+    },
+    distinguishedName: {
+      propDefinition: [
+        onelogin,
+        "distinguishedName",
+      ],
+      optional: true,
+    },
+    externalId: {
+      propDefinition: [
+        onelogin,
+        "externalId",
+      ],
+      optional: true,
+    },
+    groupId: {
+      propDefinition: [
+        onelogin,
+        "groupId",
+      ],
+      optional: true,
+    },
+    invalidLoginAttempts: {
+      propDefinition: [
+        onelogin,
+        "invalidLoginAttempts",
+      ],
+      optional: true,
+    },
+    localeCode: {
+      propDefinition: [
+        onelogin,
+        "localeCode",
+      ],
+      optional: true,
+    },
+    memberOf: {
+      propDefinition: [
+        onelogin,
+        "memberOf",
+      ],
+      optional: true,
+    },
+    openidName: {
+      propDefinition: [
+        onelogin,
+        "openidName",
+      ],
+      optional: true,
+    },
+    phone: {
+      propDefinition: [
+        onelogin,
+        "phone",
+      ],
+      optional: true,
+    },
+    samaccountname: {
+      propDefinition: [
+        onelogin,
+        "samaccountname",
+      ],
+      optional: true,
+    },
+    title: {
+      propDefinition: [
+        onelogin,
+        "title",
+      ],
+      optional: true,
+    },
+    customAttributes: {
+      propDefinition: [
+        onelogin,
+        "customAttributes",
+      ],
+      optional: true,
+    },
+    state: {
+      propDefinition: [
+        onelogin,
+        "state",
+      ],
+      optional: true,
+    },
+    status: {
+      propDefinition: [
+        onelogin,
+        "status",
+      ],
+      optional: true,
+    },
+    userprincipalname: {
+      propDefinition: [
+        onelogin,
+        "userprincipalname",
+      ],
+      optional: true,
+    },
+    managerAdId: {
+      propDefinition: [
+        onelogin,
+        "manager_ad_id",
+      ],
+      optional: true,
+    },
+    managerUserId: {
+      propDefinition: [
+        onelogin,
+        "manager_user_id",
+      ],
+      optional: true,
+    },
+    roleId: {
+      propDefinition: [
+        onelogin,
+        "role_id",
+      ],
+      optional: true,
+    },
+  },
+  async run({ $ }) {
+    const userId = this.updateUserId;
+    const data = {};
+
+    if (this.firstname) data.firstname = this.firstname;
+    if (this.lastname) data.lastname = this.lastname;
+    if (this.email) data.email = this.email;
+    if (this.username) data.username = this.username;
+    if (this.company) data.company = this.company;
+    if (this.department) data.department = this.department;
+    if (this.directoryId !== undefined) data.directory_id = this.directoryId;
+    if (this.distinguishedName) data.distinguished_name = this.distinguishedName;
+    if (this.externalId) data.external_id = this.externalId;
+    if (this.groupId) data.group_id = parseInt(this.groupId, 10);
+    if (this.invalidLoginAttempts !== undefined) data.invalid_login_attempts = this.invalidLoginAttempts;
+    if (this.localeCode) data.locale_code = this.localeCode;
+    if (this.memberOf) data.member_of = this.memberOf;
+    if (this.openidName) data.openid_name = this.openidName;
+    if (this.phone) data.phone = this.phone;
+    if (this.samaccountname) data.samaccountname = this.samaccountname;
+    if (this.title) data.title = this.title;
+    if (this.customAttributes) data.custom_attributes = this.customAttributes;
+    if (this.state !== undefined) data.state = this.state;
+    if (this.status !== undefined) data.status = this.status;
+    if (this.userprincipalname) data.userprincipalname = this.userprincipalname;
+    if (this.managerAdId) data.manager_ad_id = this.managerAdId;
+    if (this.managerUserId !== undefined) data.manager_user_id = this.managerUserId;
+    if (this.roleId) {
+      data.role_id = Array.isArray(this.roleId)
+        ? this.roleId.map((id) => parseInt(id, 10))
+        : parseInt(this.roleId, 10);
+    }
+
+    const response = await this.onelogin.updateUser(userId, data);
+    $.export("$summary", `Successfully updated user with ID ${userId}`);
+    return response;
+  },
+};
diff --git a/components/onelogin/onelogin.app.mjs b/components/onelogin/onelogin.app.mjs
index bc625b9d09792..c88ee2c3f3732 100644
--- a/components/onelogin/onelogin.app.mjs
+++ b/components/onelogin/onelogin.app.mjs
@@ -1,11 +1,375 @@
+import { axios } from "@pipedream/platform";
+
 export default {
   type: "app",
   app: "onelogin",
-  propDefinitions: {},
+  propDefinitions: {
+    // Required props for creating a new user
+    firstname: {
+      type: "string",
+      label: "First Name",
+      description: "User's first name.",
+    },
+    lastname: {
+      type: "string",
+      label: "Last Name",
+      description: "User's last name.",
+    },
+    email: {
+      type: "string",
+      label: "Email",
+      description: "User's email address.",
+      optional: true,
+    },
+    username: {
+      type: "string",
+      label: "Username",
+      description: "User's username.",
+      optional: true,
+    },
+    // Optional props for creating/updating a user
+    company: {
+      type: "string",
+      label: "Company",
+      description: "Company the user is associated with.",
+      optional: true,
+    },
+    department: {
+      type: "string",
+      label: "Department",
+      description: "Department the user works in.",
+      optional: true,
+    },
+    directoryId: {
+      type: "integer",
+      label: "Directory ID",
+      description: "ID of the directory (e.g., Active Directory, LDAP) from which the user was created.",
+      optional: true,
+    },
+    distinguishedName: {
+      type: "string",
+      label: "Distinguished Name",
+      description: "Synchronized from Active Directory.",
+      optional: true,
+    },
+    externalId: {
+      type: "string",
+      label: "External ID",
+      description: "External ID that can be used to uniquely identify the user in another system.",
+      optional: true,
+    },
+    groupId: {
+      type: "string",
+      label: "Group ID",
+      description: "Group to which the user belongs.",
+      async options() {
+        const groups = await this.listGroups();
+        return groups.map((group) => ({
+          label: group.name,
+          value: group.id.toString(),
+        }));
+      },
+      optional: true,
+    },
+    invalidLoginAttempts: {
+      type: "integer",
+      label: "Invalid Login Attempts",
+      description: "Number of sequential invalid login attempts the user has made.",
+      optional: true,
+    },
+    localeCode: {
+      type: "string",
+      label: "Locale Code",
+      description: "Locale code representing a geographical, political, or cultural region.",
+      optional: true,
+    },
+    memberOf: {
+      type: "string",
+      label: "Member Of",
+      description: "Groups the user is a member of.",
+      optional: true,
+    },
+    openidName: {
+      type: "string",
+      label: "OpenID Name",
+      description: "OpenID URL that can be configured in other applications that accept OpenID for sign-in.",
+      optional: true,
+    },
+    phone: {
+      type: "string",
+      label: "Phone",
+      description: "User's phone number.",
+      optional: true,
+    },
+    samaccountname: {
+      type: "string",
+      label: "SAMAccountName",
+      description: "Synchronized from Active Directory.",
+      optional: true,
+    },
+    title: {
+      type: "string",
+      label: "Title",
+      description: "User's title.",
+      optional: true,
+    },
+    customAttributes: {
+      type: "object",
+      label: "Custom Attributes",
+      description: "Custom attributes for the user.",
+      optional: true,
+    },
+    // Props for updating an existing user
+    updateUserId: {
+      type: "string",
+      label: "User ID",
+      description: "Unique ID of the user to update.",
+      async options() {
+        const users = await this.listUsers();
+        return users.map((user) => ({
+          label: `${user.firstname} ${user.lastname} (${user.email})`,
+          value: user.id.toString(),
+        }));
+      },
+    },
+    // Props for revoking user sessions
+    revokeUserId: {
+      type: "string",
+      label: "User ID",
+      description: "Unique ID of the user to revoke sessions for.",
+      async options() {
+        const users = await this.listUsers();
+        return users.map((user) => ({
+          label: `${user.firstname} ${user.lastname} (${user.email})`,
+          value: user.id.toString(),
+        }));
+      },
+    },
+    // Props for User Created Event Trigger filters
+    filterUserRole: {
+      type: "string",
+      label: "User Role",
+      description: "Filter by user role.",
+      async options() {
+        const roles = await this.listRoles();
+        return roles.map((role) => ({
+          label: role.name,
+          value: role.id.toString(),
+        }));
+      },
+      optional: true,
+    },
+    filterGroup: {
+      type: "string",
+      label: "Group",
+      description: "Filter by user group.",
+      async options() {
+        const groups = await this.listGroups();
+        return groups.map((group) => ({
+          label: group.name,
+          value: group.id.toString(),
+        }));
+      },
+      optional: true,
+    },
+    // Props for Login Attempt Event Trigger filters
+    filterLoginSuccess: {
+      type: "boolean",
+      label: "Successful Attempts",
+      description: "Filter to only include successful login attempts.",
+      optional: true,
+    },
+    filterLoginFailure: {
+      type: "boolean",
+      label: "Failed Attempts",
+      description: "Filter to only include failed login attempts.",
+      optional: true,
+    },
+    // Props for Directory Sync Event Trigger filters
+    directoryName: {
+      type: "string",
+      label: "Directory Name",
+      description: "Filter by specific directory name.",
+      async options() {
+        const directories = await this.listDirectories();
+        return directories.map((dir) => ({
+          label: dir.name,
+          value: dir.id.toString(),
+        }));
+      },
+      optional: true,
+    },
+    syncStatus: {
+      type: "string",
+      label: "Sync Status",
+      description: "Filter by sync status.",
+      options: [
+        {
+          label: "Success",
+          value: "success",
+        },
+        {
+          label: "Failure",
+          value: "failure",
+        },
+        {
+          label: "In Progress",
+          value: "in_progress",
+        },
+      ],
+      optional: true,
+    },
+  },
   methods: {
-    // this.$auth contains connected account data
+    // Existing method
     authKeys() {
       console.log(Object.keys(this.$auth));
     },
+    // Base URL
+    _baseUrl() {
+      return "https://api.onelogin.com/api/1";
+    },
+    // Make Request
+    async _makeRequest(opts = {}) {
+      const {
+        $ = this,
+        method = "GET",
+        path = "/",
+        data,
+        params,
+        headers = {},
+        ...otherOpts
+      } = opts;
+      return axios($, {
+        method,
+        url: this._baseUrl() + path,
+        data: data,
+        params: params,
+        headers: {
+          ...headers,
+          "Authorization": `bearer:${this.$auth.access_token}`,
+          "Content-Type": "application/json",
+        },
+        ...otherOpts,
+      });
+    },
+    // Pagination Logic
+    async paginate(fn, ...args) {
+      const results = [];
+      let page = 1;
+      let hasNext = true;
+      while (hasNext) {
+        const response = await fn({
+          page,
+          ...args,
+        });
+        if (Array.isArray(response)) {
+          results.push(...response);
+          hasNext = false;
+        } else {
+          results.push(...response);
+          hasNext = false;
+        }
+      }
+      return results;
+    },
+    // List Groups
+    async listGroups(opts = {}) {
+      return this.paginate(async ({ page }) => {
+        const response = await this._makeRequest({
+          path: "/groups",
+          params: {
+            limit: 100,
+            page,
+            ...opts.params,
+          },
+        });
+        return response;
+      }, opts);
+    },
+    // List Roles
+    async listRoles(opts = {}) {
+      return this.paginate(async ({ page }) => {
+        const response = await this._makeRequest({
+          path: "/roles",
+          params: {
+            limit: 100,
+            page,
+            ...opts.params,
+          },
+        });
+        return response;
+      }, opts);
+    },
+    // List Users
+    async listUsers(opts = {}) {
+      return this.paginate(async ({ page }) => {
+        const response = await this._makeRequest({
+          path: "/users",
+          params: {
+            limit: 100,
+            page,
+            ...opts.params,
+          },
+        });
+        return response;
+      }, opts);
+    },
+    // List Directories
+    async listDirectories(opts = {}) {
+      return this.paginate(async ({ page }) => {
+        const response = await this._makeRequest({
+          path: "/directories",
+          params: {
+            limit: 100,
+            page,
+            ...opts.params,
+          },
+        });
+        return response;
+      }, opts);
+    },
+    // Create User
+    async createUser(data, opts = {}) {
+      return this._makeRequest({
+        method: "POST",
+        path: "/users",
+        data,
+        ...opts,
+      });
+    },
+    // Update User
+    async updateUser(userId, data, opts = {}) {
+      return this._makeRequest({
+        method: "PUT",
+        path: `/users/${userId}`,
+        data,
+        ...opts,
+      });
+    },
+    // Revoke User Sessions
+    async revokeUserSessions(userId, opts = {}) {
+      return this._makeRequest({
+        method: "POST",
+        path: `/users/${userId}/logout`,
+        ...opts,
+      });
+    },
+    // Emit User Created Event
+    async emitUserCreatedEvent(filters) {
+      // Implementation to emit event based on filters
+      // This would typically involve setting up a webhook or listening to API events
+    },
+    // Emit Login Attempt Event
+    async emitLoginAttemptEvent(filters) {
+      // Implementation to emit event based on filters
+      // This would typically involve setting up a webhook or listening to API events
+    },
+    // Emit Directory Sync Event
+    async emitDirectorySyncEvent(filters) {
+      // Implementation to emit event based on filters
+      // This would typically involve setting up a webhook or listening to API events
+    },
   },
+  version: "0.0.ts",
 };
diff --git a/components/onelogin/package.json b/components/onelogin/package.json
index 687cdf4ac603b..0945197d47fa2 100644
--- a/components/onelogin/package.json
+++ b/components/onelogin/package.json
@@ -12,4 +12,4 @@
   "publishConfig": {
     "access": "public"
   }
-}
\ No newline at end of file
+}
diff --git a/components/onelogin/sources/new-directory-sync-event/new-directory-sync-event.mjs b/components/onelogin/sources/new-directory-sync-event/new-directory-sync-event.mjs
new file mode 100644
index 0000000000000..762de5d847b10
--- /dev/null
+++ b/components/onelogin/sources/new-directory-sync-event/new-directory-sync-event.mjs
@@ -0,0 +1,104 @@
+import {
+  axios, DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
+} from "@pipedream/platform";
+import onelogin from "../../onelogin.app.mjs";
+
+export default {
+  key: "onelogin-new-directory-sync-event",
+  name: "New Directory Sync Event",
+  description: "Emit new event when a directory sync event is triggered in OneLogin. [See the documentation]()",
+  version: "0.0.{{ts}}",
+  type: "source",
+  dedupe: "unique",
+  props: {
+    onelogin,
+    db: "$.service.db",
+    timer: {
+      type: "$.interface.timer",
+      default: {
+        intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
+      },
+    },
+    directoryName: {
+      propDefinition: [
+        onelogin,
+        "directoryName",
+      ],
+      optional: true,
+    },
+    syncStatus: {
+      propDefinition: [
+        onelogin,
+        "syncStatus",
+      ],
+      optional: true,
+    },
+  },
+  hooks: {
+    async deploy() {
+      const events = await this.runFetchEvents();
+      const recentEvents = events.slice(-50).reverse();
+      for (const event of recentEvents) {
+        this.$emit(
+          event,
+          {
+            id: event.id.toString(),
+            summary: `Directory Sync Event #${event.id}`,
+            ts: Date.parse(event.created_at),
+          },
+        );
+      }
+      const lastEvent = recentEvents[recentEvents.length - 1];
+      if (lastEvent) {
+        await this.db.set("last_cursor", lastEvent.id);
+      }
+    },
+    async activate() {
+      // No webhook setup required for polling source
+    },
+    async deactivate() {
+      // No webhook teardown required for polling source
+    },
+  },
+  methods: {
+    async runFetchEvents() {
+      const lastCursor = await this.db.get("last_cursor");
+      const params = {
+        event_type_id: 13,
+        limit: 50,
+        sort: "-id",
+      };
+      if (lastCursor) {
+        params.after_cursor = lastCursor;
+      }
+      if (this.directoryName) {
+        params.directory_id = this.directoryName;
+      }
+      if (this.syncStatus) {
+        params.resolution = this.syncStatus;
+      }
+      const response = await this.onelogin._makeRequest({
+        path: "/events",
+        params,
+      });
+      return response;
+    },
+  },
+  async run() {
+    const events = await this.runFetchEvents();
+    for (const event of events) {
+      this.$emit(
+        event,
+        {
+          id: event.id.toString(),
+          summary: `Directory Sync Event #${event.id}`,
+          ts: Date.parse(event.created_at),
+        },
+      );
+    }
+    if (events.length > 0) {
+      const lastEvent = events[events.length - 1];
+      await this.db.set("last_cursor", lastEvent.id);
+    }
+  },
+};
diff --git a/components/onelogin/sources/new-login-attempt/new-login-attempt.mjs b/components/onelogin/sources/new-login-attempt/new-login-attempt.mjs
new file mode 100644
index 0000000000000..f6e5f887e46e0
--- /dev/null
+++ b/components/onelogin/sources/new-login-attempt/new-login-attempt.mjs
@@ -0,0 +1,124 @@
+import {
+  axios, DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
+} from "@pipedream/platform";
+import onelogin from "../../onelogin.app.mjs";
+
+export default {
+  key: "onelogin-new-login-attempt",
+  name: "New Login Attempt",
+  description: "Emit new event when a login attempt occurs in OneLogin. [See the documentation]()",
+  version: "0.0.{{ts}}",
+  type: "source",
+  dedupe: "unique",
+  props: {
+    onelogin: {
+      type: "app",
+      app: "onelogin",
+    },
+    db: {
+      type: "$.service.db",
+    },
+    timer: {
+      type: "$.interface.timer",
+      default: {
+        intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
+      },
+    },
+    filterLoginSuccess: {
+      propDefinition: [
+        "onelogin",
+        "filterLoginSuccess",
+      ],
+    },
+    filterLoginFailure: {
+      propDefinition: [
+        "onelogin",
+        "filterLoginFailure",
+      ],
+    },
+  },
+  hooks: {
+    async deploy() {
+      await this.fetchAndEmitEvents(true);
+    },
+    async activate() {
+      // No webhook setup required for polling source
+    },
+    async deactivate() {
+      // No webhook cleanup required for polling source
+    },
+  },
+  methods: {
+    async fetchAndEmitEvents(isDeploy = false) {
+      const lastCursor = await this.db.get("after_cursor");
+      const params = {
+        limit: 50,
+        sort: "-created_at",
+      };
+
+      if (lastCursor) {
+        params.after_cursor = lastCursor;
+      }
+
+      // Define event_type_ids that correspond to login attempts
+      // These IDs should be replaced with actual ones from OneLogin
+      const loginAttemptEventTypeIds = [
+        5,
+        13,
+      ];
+      params.event_type_id = loginAttemptEventTypeIds.join(",");
+
+      const response = await this.onelogin._makeRequest({
+        path: "/events",
+        params,
+      });
+
+      const events = response;
+
+      // Emit events from oldest to newest
+      for (const event of events.reverse()) {
+        if (this._isLoginAttempt(event) && this._matchesFilters(event)) {
+          const eventId = event.id
+            ? event.id.toString()
+            : undefined;
+          const eventTimestamp = event.created_at
+            ? Date.parse(event.created_at)
+            : Date.now();
+          const emitMeta = {
+            id: eventId || undefined,
+            summary: `Login attempt by ${event.user_name}`,
+            ts: eventTimestamp,
+          };
+          this.$emit(event, emitMeta);
+        }
+      }
+
+      // Update the cursor
+      if (events.length > 0 && response.pagination && response.pagination.after_cursor) {
+        await this.db.set("after_cursor", response.pagination.after_cursor);
+      }
+    },
+    _isLoginAttempt(event) {
+      return [
+        5,
+        13,
+      ].includes(event.event_type_id);
+    },
+    _matchesFilters(event) {
+      let isSuccess = !event.error_description;
+      if (this.filterLoginSuccess && isSuccess) {
+        return true;
+      }
+      if (this.filterLoginFailure && !isSuccess) {
+        return true;
+      }
+      if (!this.filterLoginSuccess && !this.filterLoginFailure) {
+        return true;
+      }
+      return false;
+    },
+  },
+  async run() {
+    await this.fetchAndEmitEvents();
+  },
+};
diff --git a/components/onelogin/sources/new-user/new-user.mjs b/components/onelogin/sources/new-user/new-user.mjs
new file mode 100644
index 0000000000000..6b6a60967cdda
--- /dev/null
+++ b/components/onelogin/sources/new-user/new-user.mjs
@@ -0,0 +1,102 @@
+import {
+  axios, DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
+} from "@pipedream/platform";
+import onelogin from "../../onelogin.app.mjs";
+
+export default {
+  key: "onelogin-new-user",
+  name: "New User Created",
+  description: "Emit a new event when a user is created in OneLogin. [See the documentation]().",
+  version: "0.0.{{ts}}",
+  type: "source",
+  dedupe: "unique",
+  props: {
+    onelogin,
+    db: "$.service.db",
+    timer: {
+      type: "$.interface.timer",
+      default: {
+        intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
+      },
+    },
+    filterUserRole: {
+      propDefinition: [
+        onelogin,
+        "filterUserRole",
+      ],
+      optional: true,
+    },
+    filterGroup: {
+      propDefinition: [
+        onelogin,
+        "filterGroup",
+      ],
+      optional: true,
+    },
+  },
+  hooks: {
+    async deploy() {
+      const lastRun = this.db.get("lastRun");
+      const now = new Date().toISOString();
+      const since = lastRun || new Date(Date.now() - this.timer.intervalSeconds * 1000).toISOString();
+      const params = {
+        event_type_id: "13",
+        since,
+        limit: 50,
+        sort: "-created_at",
+      };
+      const events = await this.onelogin._makeRequest({
+        path: "/events",
+        params,
+      });
+      for (const event of events) {
+        if (this.filterUserRole && event.role_id !== parseInt(this.filterUserRole, 10)) {
+          continue;
+        }
+        if (this.filterGroup && event.group_id !== parseInt(this.filterGroup, 10)) {
+          continue;
+        }
+        this.$emit(event, {
+          id: event.id.toString(),
+          summary: `New user created: ${event.user_name}`,
+          ts: Date.parse(event.created_at) || Date.now(),
+        });
+      }
+      this.db.set("lastRun", now);
+    },
+    async activate() {
+      // No webhook setup required for polling source
+    },
+    async deactivate() {
+      // No webhook cleanup required for polling source
+    },
+  },
+  async run() {
+    const lastRun = this.db.get("lastRun");
+    const now = new Date().toISOString();
+    const params = {
+      event_type_id: "13",
+      since: lastRun || new Date(Date.now() - this.timer.intervalSeconds * 1000).toISOString(),
+      limit: 100,
+      sort: "-created_at",
+    };
+    const events = await this.onelogin._makeRequest({
+      path: "/events",
+      params,
+    });
+    for (const event of events) {
+      if (this.filterUserRole && event.role_id !== parseInt(this.filterUserRole, 10)) {
+        continue;
+      }
+      if (this.filterGroup && event.group_id !== parseInt(this.filterGroup, 10)) {
+        continue;
+      }
+      this.$emit(event, {
+        id: event.id.toString(),
+        summary: `New user created: ${event.user_name}`,
+        ts: Date.parse(event.created_at) || Date.now(),
+      });
+    }
+    this.db.set("lastRun", now);
+  },
+};

From 077473881d556d7f41af1f3df8525834eaedbe02 Mon Sep 17 00:00:00 2001
From: Luan Cazarine <luanhc@gmail.com>
Date: Fri, 14 Feb 2025 11:42:48 -0300
Subject: [PATCH 2/3] some adjusts

---
 .../actions/create-user/create-user.mjs       | 114 ++++------------
 components/onelogin/common/utils.mjs          |  24 ++++
 components/onelogin/onelogin.app.mjs          | 124 ++++++------------
 3 files changed, 87 insertions(+), 175 deletions(-)
 create mode 100644 components/onelogin/common/utils.mjs

diff --git a/components/onelogin/actions/create-user/create-user.mjs b/components/onelogin/actions/create-user/create-user.mjs
index 7f3a52a1d4a8e..5847e19354679 100644
--- a/components/onelogin/actions/create-user/create-user.mjs
+++ b/components/onelogin/actions/create-user/create-user.mjs
@@ -1,5 +1,6 @@
+import { ConfigurationError } from "@pipedream/platform";
+import { parseObject } from "../../common/utils.mjs";
 import onelogin from "../../onelogin.app.mjs";
-import { axios } from "@pipedream/platform";
 
 export default {
   key: "onelogin-create-user",
@@ -136,95 +137,32 @@ export default {
   },
   async run({ $ }) {
     if (!this.email && !this.username) {
-      throw new Error("Either email or username must be provided.");
+      throw new ConfigurationError("Either email or username must be provided.");
     }
 
-    const userData = {
-      firstname: this.firstname,
-      lastname: this.lastname,
-      ...(this.email
-        ? {
-          email: this.email,
-        }
-        : {}),
-      ...(this.username
-        ? {
-          username: this.username,
-        }
-        : {}),
-      ...(this.company != null
-        ? {
-          company: this.company,
-        }
-        : {}),
-      ...(this.department != null
-        ? {
-          department: this.department,
-        }
-        : {}),
-      ...(this.directoryId != null
-        ? {
-          directory_id: this.directoryId,
-        }
-        : {}),
-      ...(this.distinguishedName != null
-        ? {
-          distinguished_name: this.distinguishedName,
-        }
-        : {}),
-      ...(this.externalId != null
-        ? {
-          external_id: this.externalId,
-        }
-        : {}),
-      ...(this.groupId != null
-        ? {
-          group_id: parseInt(this.groupId, 10),
-        }
-        : {}),
-      ...(this.invalidLoginAttempts != null
-        ? {
-          invalid_login_attempts: this.invalidLoginAttempts,
-        }
-        : {}),
-      ...(this.localeCode != null
-        ? {
-          locale_code: this.localeCode,
-        }
-        : {}),
-      ...(this.memberOf != null
-        ? {
-          member_of: this.memberOf,
-        }
-        : {}),
-      ...(this.openidName != null
-        ? {
-          openid_name: this.openidName,
-        }
-        : {}),
-      ...(this.phone != null
-        ? {
-          phone: this.phone,
-        }
-        : {}),
-      ...(this.samaccountname != null
-        ? {
-          samaccountname: this.samaccountname,
-        }
-        : {}),
-      ...(this.title != null
-        ? {
-          title: this.title,
-        }
-        : {}),
-      ...(this.customAttributes != null
-        ? {
-          custom_attributes: this.customAttributes,
-        }
-        : {}),
-    };
-
-    const response = await this.onelogin.createUser(userData);
+    const response = await this.onelogin.createUser({
+      $,
+      data: {
+        firstname: this.firstname,
+        lastname: this.lastname,
+        email: this.email,
+        username: this.username,
+        company: this.company,
+        department: this.department,
+        directory_id: this.directoryId,
+        distinguished_name: this.distinguishedName,
+        external_id: this.externalId,
+        group_id: this.groupId,
+        invalid_login_attempts: this.invalidLoginAttempts,
+        locale_code: this.localeCode,
+        member_of: this.memberOf,
+        openid_name: this.openidName,
+        phone: this.phone,
+        samaccountname: this.samaccountname,
+        title: this.title,
+        custom_attributes: parseObject(this.customAttributes),
+      },
+    });
 
     $.export("$summary", `Created user ${response.username} with ID ${response.id}`);
     return response;
diff --git a/components/onelogin/common/utils.mjs b/components/onelogin/common/utils.mjs
new file mode 100644
index 0000000000000..dcc9cc61f6f41
--- /dev/null
+++ b/components/onelogin/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/onelogin/onelogin.app.mjs b/components/onelogin/onelogin.app.mjs
index c88ee2c3f3732..b17e8b512a708 100644
--- a/components/onelogin/onelogin.app.mjs
+++ b/components/onelogin/onelogin.app.mjs
@@ -59,7 +59,7 @@ export default {
       optional: true,
     },
     groupId: {
-      type: "string",
+      type: "integer",
       label: "Group ID",
       description: "Group to which the user belongs.",
       async options() {
@@ -221,38 +221,34 @@ export default {
     },
   },
   methods: {
-    // Existing method
-    authKeys() {
-      console.log(Object.keys(this.$auth));
-    },
-    // Base URL
     _baseUrl() {
-      return "https://api.onelogin.com/api/1";
-    },
-    // Make Request
-    async _makeRequest(opts = {}) {
-      const {
-        $ = this,
-        method = "GET",
-        path = "/",
-        data,
-        params,
-        headers = {},
-        ...otherOpts
-      } = opts;
-      return axios($, {
-        method,
+      return `https://${this.$auth.subdomain}.onelogin.com/api/1`;
+    },
+    _headers() {
+      return {
+        Authorization: `Bearer ${this.$auth.oauth_access_token}`,
+      };
+    },
+    _makeRequest({
+      $ = this, path, ...opts
+    }) {
+      const config = {
         url: this._baseUrl() + path,
-        data: data,
-        params: params,
-        headers: {
-          ...headers,
-          "Authorization": `bearer:${this.$auth.access_token}`,
-          "Content-Type": "application/json",
-        },
-        ...otherOpts,
+        headers: this._headers(),
+        ...opts,
+      };
+      console.log("config: ", config);
+      return axios($, config);
+    },
+    createUser(data, opts = {}) {
+      return this._makeRequest({
+        method: "POST",
+        path: "/users",
+        data,
+        ...opts,
       });
     },
+
     // Pagination Logic
     async paginate(fn, ...args) {
       const results = [];
@@ -275,45 +271,24 @@ export default {
     },
     // List Groups
     async listGroups(opts = {}) {
-      return this.paginate(async ({ page }) => {
-        const response = await this._makeRequest({
-          path: "/groups",
-          params: {
-            limit: 100,
-            page,
-            ...opts.params,
-          },
-        });
-        return response;
-      }, opts);
+      return this._makeRequest({
+        path: "/groups",
+        ...opts,
+      });
     },
     // List Roles
     async listRoles(opts = {}) {
-      return this.paginate(async ({ page }) => {
-        const response = await this._makeRequest({
-          path: "/roles",
-          params: {
-            limit: 100,
-            page,
-            ...opts.params,
-          },
-        });
-        return response;
-      }, opts);
+      return this._makeRequest({
+        path: "/roles",
+        ...opts,
+      });
     },
     // List Users
     async listUsers(opts = {}) {
-      return this.paginate(async ({ page }) => {
-        const response = await this._makeRequest({
-          path: "/users",
-          params: {
-            limit: 100,
-            page,
-            ...opts.params,
-          },
-        });
-        return response;
-      }, opts);
+      return this._makeRequest({
+        path: "/users",
+        ...opts,
+      });
     },
     // List Directories
     async listDirectories(opts = {}) {
@@ -329,15 +304,6 @@ export default {
         return response;
       }, opts);
     },
-    // Create User
-    async createUser(data, opts = {}) {
-      return this._makeRequest({
-        method: "POST",
-        path: "/users",
-        data,
-        ...opts,
-      });
-    },
     // Update User
     async updateUser(userId, data, opts = {}) {
       return this._makeRequest({
@@ -355,21 +321,5 @@ export default {
         ...opts,
       });
     },
-    // Emit User Created Event
-    async emitUserCreatedEvent(filters) {
-      // Implementation to emit event based on filters
-      // This would typically involve setting up a webhook or listening to API events
-    },
-    // Emit Login Attempt Event
-    async emitLoginAttemptEvent(filters) {
-      // Implementation to emit event based on filters
-      // This would typically involve setting up a webhook or listening to API events
-    },
-    // Emit Directory Sync Event
-    async emitDirectorySyncEvent(filters) {
-      // Implementation to emit event based on filters
-      // This would typically involve setting up a webhook or listening to API events
-    },
   },
-  version: "0.0.ts",
 };

From 4d54b6e2b016ec28872db9ea9fb97e249698c259 Mon Sep 17 00:00:00 2001
From: Luan Cazarine <luanhc@gmail.com>
Date: Fri, 14 Feb 2025 11:43:57 -0300
Subject: [PATCH 3/3] pnpm update

---
 pnpm-lock.yaml | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 83d4926f198d0..98ff93acf9b7b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -774,8 +774,7 @@ importers:
         specifier: ^2.3.3
         version: 2.3.3
 
-  components/applicantstack:
-    specifiers: {}
+  components/applicantstack: {}
 
   components/appointedd:
     dependencies:
@@ -3613,8 +3612,7 @@ importers:
         specifier: ^1.2.0
         version: 1.6.6
 
-  components/felt:
-    specifiers: {}
+  components/felt: {}
 
   components/fibery:
     dependencies:
@@ -7585,8 +7583,7 @@ importers:
         specifier: ^3.0.3
         version: 3.0.3
 
-  components/ory:
-    specifiers: {}
+  components/ory: {}
 
   components/osu: {}
 
@@ -12419,8 +12416,7 @@ importers:
         specifier: ^3.0.3
         version: 3.0.3
 
-  components/zep:
-    specifiers: {}
+  components/zep: {}
 
   components/zerobounce:
     dependencies: