diff --git a/components/teamwork/actions/create-task/create-task.mjs b/components/teamwork/actions/create-task/create-task.mjs index 1ee06929317f4..f86454a317295 100644 --- a/components/teamwork/actions/create-task/create-task.mjs +++ b/components/teamwork/actions/create-task/create-task.mjs @@ -3,7 +3,7 @@ import app from "../../teamwork.app.mjs"; export default { type: "action", key: "teamwork-create-task", - version: "0.0.1", + version: "0.0.2", name: "Create Task", description: "Create a new task in the backlog. [See the docs here](https://apidocs.teamwork.com/docs/teamwork/cd8948166b1b1-create-a-task)", props: { diff --git a/components/teamwork/actions/create-user/create-user.mjs b/components/teamwork/actions/create-user/create-user.mjs new file mode 100644 index 0000000000000..a6d1bf11ca12a --- /dev/null +++ b/components/teamwork/actions/create-user/create-user.mjs @@ -0,0 +1,488 @@ +import app from "../../teamwork.app.mjs"; +import { parseObject } from "../../common/utils.mjs"; + +export default { + type: "action", + key: "teamwork-create-user", + version: "0.0.1", + name: "Create User", + description: "Create a new user in Teamwork. [See the docs here](https://apidocs.teamwork.com/docs/teamwork/v1/people/post-people-json)", + props: { + app, + emailAddress: { + type: "string", + label: "Email Address", + description: "The email address of the person", + }, + firstName: { + type: "string", + label: "First Name", + description: "The first name of the person", + }, + lastName: { + type: "string", + label: "Last Name", + description: "The last name of the person", + }, + companyId: { + propDefinition: [ + app, + "companyId", + ], + }, + sendInvite: { + type: "boolean", + label: "Send Invite", + description: "Whether to send an invitation email to the new user", + optional: true, + }, + title: { + type: "string", + label: "Title", + description: "The job title of the person", + optional: true, + }, + phoneNumberOffice: { + type: "string", + label: "Office Phone", + description: "The office phone number of the person", + optional: true, + }, + phoneNumberOfficeExt: { + type: "string", + label: "Office Phone Extension", + description: "The office phone extension of the person", + optional: true, + }, + phoneNumberMobileCountrycode: { + type: "string", + label: "Mobile Phone Country Code", + description: "The country code for the mobile phone number", + optional: true, + }, + phoneNumberMobilePrefix: { + type: "string", + label: "Mobile Phone Prefix", + description: "The prefix for the mobile phone number", + optional: true, + }, + phoneNumberMobile: { + type: "string", + label: "Mobile Phone", + description: "The mobile phone number of the person", + optional: true, + }, + phoneNumberHome: { + type: "string", + label: "Home Phone", + description: "The home phone number of the person", + optional: true, + }, + phoneNumberFax: { + type: "string", + label: "Fax Number", + description: "The fax number of the person", + optional: true, + }, + emailAlt1: { + type: "string", + label: "Alternative Email 1", + description: "First alternative email address", + optional: true, + }, + emailAlt2: { + type: "string", + label: "Alternative Email 2", + description: "Second alternative email address", + optional: true, + }, + emailAlt3: { + type: "string", + label: "Alternative Email 3", + description: "Third alternative email address", + optional: true, + }, + address: { + type: "object", + label: "Address", + description: "Object containing address information. [See the documentation](https://apidocs.teamwork.com/docs/teamwork/v1/people/post-people-json) for more information.", + optional: true, + }, + profile: { + type: "string", + label: "Profile", + description: "The profile information of the person", + optional: true, + }, + userTwitterName: { + type: "string", + label: "Twitter Name", + description: "The Twitter handle of the person", + optional: true, + }, + userLinkedin: { + type: "string", + label: "LinkedIn", + description: "The LinkedIn profile URL of the person", + optional: true, + }, + userFacebook: { + type: "string", + label: "Facebook", + description: "The Facebook profile URL of the person", + optional: true, + }, + userWebsite: { + type: "string", + label: "Website", + description: "The personal website of the person", + optional: true, + }, + imService: { + type: "string", + label: "IM Service", + description: "The instant messaging service used by the person", + optional: true, + }, + imHandle: { + type: "string", + label: "IM Handle", + description: "The instant messaging username of the person", + optional: true, + }, + language: { + type: "string", + label: "Language", + description: "The language preference for the person", + optional: true, + }, + dateFormatId: { + type: "integer", + label: "Date Format ID", + description: "The date format ID for the person", + optional: true, + }, + timeFormatId: { + type: "integer", + label: "Time Format ID", + description: "The time format ID for the person", + optional: true, + }, + timezoneId: { + type: "integer", + label: "Timezone ID", + description: "The timezone ID for the person", + optional: true, + }, + calendarStartsOnSunday: { + type: "string", + label: "Calendar Starts On Sunday", + description: "Whether the calendar starts on Sunday", + optional: true, + }, + lengthOfDay: { + type: "integer", + label: "Length of Day", + description: "The length of day in hours", + optional: true, + }, + workingHours: { + type: "object", + label: "Working Hours", + description: "Object containing working hours information. . [See the documentation](https://apidocs.teamwork.com/docs/teamwork/v1/people/post-people-json) for more information.", + optional: true, + }, + changeForEveryone: { + type: "boolean", + label: "Change For Everyone", + description: "Whether changes apply to everyone", + optional: true, + }, + administrator: { + type: "boolean", + label: "Administrator", + description: "Whether the person is an administrator", + optional: true, + }, + canAddProjects: { + type: "boolean", + label: "Can Add Projects", + description: "Whether the person can add projects", + optional: true, + }, + canManagePeople: { + type: "boolean", + label: "Can Manage People", + description: "Whether the person can manage people", + optional: true, + }, + autoGiveProjectAccess: { + type: "boolean", + label: "Auto Give Project Access", + description: "Whether to automatically give the person access to new projects", + optional: true, + }, + canAccessCalendar: { + type: "boolean", + label: "Can Access Calendar", + description: "Whether the person can access the calendar", + optional: true, + }, + canAccessTemplates: { + type: "boolean", + label: "Can Access Templates", + description: "Whether the person can access templates", + optional: true, + }, + canAccessPortfolio: { + type: "boolean", + label: "Can Access Portfolio", + description: "Whether the person can access the portfolio", + optional: true, + }, + canManageCustomFields: { + type: "boolean", + label: "Can Manage Custom Fields", + description: "Whether the person can manage custom fields", + optional: true, + }, + canManagePortfolio: { + type: "boolean", + label: "Can Manage Portfolio", + description: "Whether the person can manage the portfolio", + optional: true, + }, + canManageProjectTemplates: { + type: "boolean", + label: "Can Manage Project Templates", + description: "Whether the person can manage project templates", + optional: true, + }, + canViewProjectTemplates: { + type: "boolean", + label: "Can View Project Templates", + description: "Whether the person can view project templates", + optional: true, + }, + notifyOnTaskComplete: { + type: "boolean", + label: "Notify On Task Complete", + description: "Whether to notify when tasks are completed", + optional: true, + }, + notifyOnAddedAsFollower: { + type: "boolean", + label: "Notify On Added As Follower", + description: "Whether to notify when added as a follower", + optional: true, + }, + notifyOnStatusUpdate: { + type: "boolean", + label: "Notify On Status Update", + description: "Whether to notify on status updates", + optional: true, + }, + textFormat: { + type: "string", + label: "Text Format", + description: "The text format preference", + optional: true, + }, + useShorthandDurations: { + type: "boolean", + label: "Use Shorthand Durations", + description: "Whether to use shorthand durations", + optional: true, + }, + userReceiveNotifyWarnings: { + type: "boolean", + label: "User Receive Notify Warnings", + description: "Whether the user receives notification warnings", + optional: true, + }, + userReceiveMyNotificationsOnly: { + type: "boolean", + label: "User Receive My Notifications Only", + description: "Whether the user receives only their own notifications", + optional: true, + }, + receiveDailyReports: { + type: "boolean", + label: "Receive Daily Reports", + description: "Whether the person should receive daily reports", + optional: true, + }, + receiveDailyReportsAtWeekend: { + type: "boolean", + label: "Receive Daily Reports At Weekend", + description: "Whether to receive daily reports on weekends", + optional: true, + }, + receiveDailyReportsIfEmpty: { + type: "boolean", + label: "Receive Daily Reports If Empty", + description: "Whether to receive daily reports even if empty", + optional: true, + }, + soundAlertsEnabled: { + type: "boolean", + label: "Sound Alerts Enabled", + description: "Whether sound alerts are enabled", + optional: true, + }, + dailyReportSort: { + type: "string", + label: "Daily Report Sort", + description: "The sort order for daily reports", + optional: true, + }, + receiveDailyReportsAtTime: { + type: "string", + label: "Receive Daily Reports At Time", + description: "The time to receive daily reports", + optional: true, + }, + dailyReportEventsType: { + type: "string", + label: "Daily Report Events Type", + description: "The type of events for daily reports", + optional: true, + }, + dailyReportDaysFilter: { + type: "integer", + label: "Daily Report Days Filter", + description: "The days filter for daily reports", + optional: true, + }, + avatarPendingFileRef: { + type: "string", + label: "Avatar Pending File Ref", + description: "Reference to pending avatar file", + optional: true, + }, + removeAvatar: { + type: "boolean", + label: "Remove Avatar", + description: "Whether to remove the avatar", + optional: true, + }, + allowEmailNotifications: { + type: "boolean", + label: "Allow Email Notifications", + description: "Whether to allow email notifications", + optional: true, + }, + userType: { + type: "string", + label: "User Type", + description: "The type of user (account, collaborator, contact)", + optional: true, + options: [ + { + label: "Account", + value: "account", + }, + { + label: "Collaborator", + value: "collaborator", + }, + { + label: "Contact", + value: "contact", + }, + ], + }, + privateNotes: { + type: "string", + label: "Private Notes", + description: "Private notes about the person", + optional: true, + }, + getUserDetails: { + type: "boolean", + label: "Get User Details", + description: "Whether to return user details in the response", + optional: true, + }, + }, + async run({ $ }) { + const data = { + "email-address": this.emailAddress, + "first-name": this.firstName, + "last-name": this.lastName, + "company-id": this.companyId, + "sendInvite": this.sendInvite, + "title": this.title, + "phone-number-office": this.phoneNumberOffice, + "phone-number-office-ext": this.phoneNumberOfficeExt, + "phone-number-mobile-countrycode": this.phoneNumberMobileCountrycode, + "phone-number-mobile-prefix": this.phoneNumberMobilePrefix, + "phone-number-mobile": this.phoneNumberMobile, + "phone-number-home": this.phoneNumberHome, + "phone-number-fax": this.phoneNumberFax, + "email-alt-1": this.emailAlt1, + "email-alt-2": this.emailAlt2, + "email-alt-3": this.emailAlt3, + "address": parseObject(this.address), + "profile": this.profile, + "userTwitterName": this.userTwitterName, + "userLinkedin": this.userLinkedin, + "userFacebook": this.userFacebook, + "userWebsite": this.userWebsite, + "im-service": this.imService, + "im-handle": this.imHandle, + "language": this.language, + "dateFormatId": this.dateFormatId, + "timeFormatId": this.timeFormatId, + "timezoneId": this.timezoneId, + "calendarStartsOnSunday": this.calendarStartsOnSunday, + "lengthOfDay": this.lengthOfDay, + "workingHours": parseObject(this.workingHours), + "changeForEveryone": this.changeForEveryone, + "administrator": this.administrator, + "canAddProjects": this.canAddProjects, + "canManagePeople": this.canManagePeople, + "autoGiveProjectAccess": this.autoGiveProjectAccess, + "canAccessCalendar": this.canAccessCalendar, + "canAccessTemplates": this.canAccessTemplates, + "canAccessPortfolio": this.canAccessPortfolio, + "canManageCustomFields": this.canManageCustomFields, + "canManagePortfolio": this.canManagePortfolio, + "canManageProjectTemplates": this.canManageProjectTemplates, + "canViewProjectTemplates": this.canViewProjectTemplates, + "notifyOnTaskComplete": this.notifyOnTaskComplete, + "notify-on-added-as-follower": this.notifyOnAddedAsFollower, + "notify-on-status-update": this.notifyOnStatusUpdate, + "textFormat": this.textFormat, + "useShorthandDurations": this.useShorthandDurations, + "userReceiveNotifyWarnings": this.userReceiveNotifyWarnings, + "userReceiveMyNotificationsOnly": this.userReceiveMyNotificationsOnly, + "receiveDailyReports": this.receiveDailyReports, + "receiveDailyReportsAtWeekend": this.receiveDailyReportsAtWeekend, + "receiveDailyReportsIfEmpty": this.receiveDailyReportsIfEmpty, + "soundAlertsEnabled": this.soundAlertsEnabled, + "dailyReportSort": this.dailyReportSort, + "receiveDailyReportsAtTime": this.receiveDailyReportsAtTime, + "dailyReportEventsType": this.dailyReportEventsType, + "dailyReportDaysFilter": this.dailyReportDaysFilter, + "avatarPendingFileRef": this.avatarPendingFileRef, + "removeAvatar": this.removeAvatar, + "allowEmailNotifications": this.allowEmailNotifications, + "user-type": this.userType, + "privateNotes": this.privateNotes, + "getUserDetails": this.getUserDetails, + }; + + // Remove undefined values + Object.keys(data).forEach((key) => { + if (data[key] === undefined) { + delete data[key]; + } + }); + + const response = await this.app.createPerson(data, $); + + $.export("$summary", `User ${this.firstName} ${this.lastName} created successfully`); + return response; + }, +}; diff --git a/components/teamwork/actions/delete-task/delete-task.mjs b/components/teamwork/actions/delete-task/delete-task.mjs index 89a62d6460e67..43aed96d8f6d6 100644 --- a/components/teamwork/actions/delete-task/delete-task.mjs +++ b/components/teamwork/actions/delete-task/delete-task.mjs @@ -5,7 +5,7 @@ export default { key: "teamwork-delete-task", name: "Delete Task", description: "Delete a task. [See the docs here](https://apidocs.teamwork.com/docs/teamwork/67114797aa90c-delete-a-task)", - version: "0.0.1", + version: "0.0.2", props: { app, projectId: { diff --git a/components/teamwork/actions/get-user/get-user.mjs b/components/teamwork/actions/get-user/get-user.mjs new file mode 100644 index 0000000000000..24234934626b7 --- /dev/null +++ b/components/teamwork/actions/get-user/get-user.mjs @@ -0,0 +1,25 @@ +import app from "../../teamwork.app.mjs"; + +export default { + key: "teamwork-get-user", + name: "Get User", + description: "Get a user by ID. [See the documentation](https://apidocs.teamwork.com/docs/teamwork/v1/people/get-people-id-json)", + version: "0.0.1", + type: "action", + props: { + app, + peopleId: { + propDefinition: [ + app, + "peopleId", + ], + label: "User ID", + description: "The ID of the user/person to get", + }, + }, + async run({ $ }) { + const user = await this.app.getPerson(this.peopleId, $); + $.export("$summary", `Found user ${user["first-name"]} ${user["last-name"]}`); + return user; + }, +}; diff --git a/components/teamwork/actions/list-project-tasks/list-project-tasks.mjs b/components/teamwork/actions/list-project-tasks/list-project-tasks.mjs index 960b848281d69..01aac074df6ce 100644 --- a/components/teamwork/actions/list-project-tasks/list-project-tasks.mjs +++ b/components/teamwork/actions/list-project-tasks/list-project-tasks.mjs @@ -5,7 +5,7 @@ export default { key: "teamwork-list-project-tasks", name: "List Project Tasks", description: "List tasks from a project. [See the docs here](https://apidocs.teamwork.com/docs/teamwork/6e3da2c04d779-get-all-tasks-on-a-given-project)", - version: "0.0.1", + version: "0.0.2", props: { app, projectId: { diff --git a/components/teamwork/actions/list-users/list-users.mjs b/components/teamwork/actions/list-users/list-users.mjs new file mode 100644 index 0000000000000..72f44443ae0e7 --- /dev/null +++ b/components/teamwork/actions/list-users/list-users.mjs @@ -0,0 +1,73 @@ +import app from "../../teamwork.app.mjs"; + +export default { + key: "teamwork-list-users", + name: "List Users", + description: "List all users. [See the documentation](https://apidocs.teamwork.com/docs/teamwork/v1/people/get-people-json)", + version: "0.0.1", + type: "action", + props: { + app, + sort: { + type: "string", + label: "Sort", + description: "The field to sort by", + optional: true, + options: [ + "company", + "logincount", + "lastlogin", + "projectlastactive", + "firstName", + "lastName", + "title", + "dateAdded", + ], + }, + sortDirection: { + type: "string", + label: "Sort Direction", + description: "The direction to sort by", + optional: true, + options: [ + "asc", + "desc", + ], + }, + maxResults: { + type: "integer", + label: "Max Results", + description: "The maximum number of results to return", + optional: true, + default: 100, + }, + }, + async run({ $ }) { + let total, count = 0, page = 1; + let users = []; + const params = { + sort: this.sort, + sortOrder: this.sortDirection, + pageSize: 100, + }; + do { + const items = await this.app.listPeople(page, $, params); + total = items?.length; + if (!total) { + break; + } + users.push(...items); + count += items.length; + page++; + } while (count < this.maxResults); + + if (users.length > this.maxResults) { + users = users.slice(0, this.maxResults); + } + + $.export("$summary", `Found ${users.length} user${users.length === 1 + ? "" + : "s"}`); + return users; + }, +}; diff --git a/components/teamwork/actions/update-task/update-task.mjs b/components/teamwork/actions/update-task/update-task.mjs index 9255f63508e16..4cd8921b3ccf5 100644 --- a/components/teamwork/actions/update-task/update-task.mjs +++ b/components/teamwork/actions/update-task/update-task.mjs @@ -5,7 +5,7 @@ export default { key: "teamwork-update-task", name: "Update Task", description: "Update a task. [See the docs here](https://apidocs.teamwork.com/docs/teamwork/6e3da2c04d779-update-a-task)", - version: "0.0.1", + version: "0.0.2", props: { app, projectId: { diff --git a/components/teamwork/actions/update-user/update-user.mjs b/components/teamwork/actions/update-user/update-user.mjs new file mode 100644 index 0000000000000..eccdec865bcc1 --- /dev/null +++ b/components/teamwork/actions/update-user/update-user.mjs @@ -0,0 +1,489 @@ +import app from "../../teamwork.app.mjs"; +import { parseObject } from "../../common/utils.mjs"; + +export default { + key: "teamwork-update-user", + name: "Update User", + description: "Update a user in Teamwork. [See the documentation](https://apidocs.teamwork.com/docs/teamwork/v1/people/put-people-id-json)", + version: "0.0.1", + type: "action", + props: { + app, + peopleId: { + propDefinition: [ + app, + "peopleId", + ], + label: "User ID", + description: "The ID of the user to update", + }, + emailAddress: { + type: "string", + label: "Email Address", + description: "The email address of the person", + optional: true, + }, + firstName: { + type: "string", + label: "First Name", + description: "The first name of the person", + optional: true, + }, + lastName: { + type: "string", + label: "Last Name", + description: "The last name of the person", + optional: true, + }, + companyId: { + propDefinition: [ + app, + "companyId", + ], + }, + sendInvite: { + type: "boolean", + label: "Send Invite", + description: "Whether to send an invitation email to the new user", + optional: true, + }, + title: { + type: "string", + label: "Title", + description: "The job title of the person", + optional: true, + }, + phoneNumberOffice: { + type: "string", + label: "Office Phone", + description: "The office phone number of the person", + optional: true, + }, + phoneNumberOfficeExt: { + type: "string", + label: "Office Phone Extension", + description: "The office phone extension of the person", + optional: true, + }, + phoneNumberMobileCountrycode: { + type: "string", + label: "Mobile Phone Country Code", + description: "The country code for the mobile phone number", + optional: true, + }, + phoneNumberMobilePrefix: { + type: "string", + label: "Mobile Phone Prefix", + description: "The prefix for the mobile phone number", + optional: true, + }, + phoneNumberMobile: { + type: "string", + label: "Mobile Phone", + description: "The mobile phone number of the person", + optional: true, + }, + phoneNumberHome: { + type: "string", + label: "Home Phone", + description: "The home phone number of the person", + optional: true, + }, + phoneNumberFax: { + type: "string", + label: "Fax Number", + description: "The fax number of the person", + optional: true, + }, + emailAlt1: { + type: "string", + label: "Alternative Email 1", + description: "First alternative email address", + optional: true, + }, + emailAlt2: { + type: "string", + label: "Alternative Email 2", + description: "Second alternative email address", + optional: true, + }, + emailAlt3: { + type: "string", + label: "Alternative Email 3", + description: "Third alternative email address", + optional: true, + }, + address: { + type: "object", + label: "Address", + description: "Object containing address information. [See the documentation](https://apidocs.teamwork.com/docs/teamwork/v1/people/post-people-json) for more information.", + optional: true, + }, + profile: { + type: "string", + label: "Profile", + description: "The profile information of the person", + optional: true, + }, + userTwitterName: { + type: "string", + label: "Twitter Name", + description: "The Twitter handle of the person", + optional: true, + }, + userLinkedin: { + type: "string", + label: "LinkedIn", + description: "The LinkedIn profile URL of the person", + optional: true, + }, + userFacebook: { + type: "string", + label: "Facebook", + description: "The Facebook profile URL of the person", + optional: true, + }, + userWebsite: { + type: "string", + label: "Website", + description: "The personal website of the person", + optional: true, + }, + imService: { + type: "string", + label: "IM Service", + description: "The instant messaging service used by the person", + optional: true, + }, + imHandle: { + type: "string", + label: "IM Handle", + description: "The instant messaging username of the person", + optional: true, + }, + language: { + type: "string", + label: "Language", + description: "The language preference for the person", + optional: true, + }, + dateFormatId: { + type: "integer", + label: "Date Format ID", + description: "The date format ID for the person", + optional: true, + }, + timeFormatId: { + type: "integer", + label: "Time Format ID", + description: "The time format ID for the person", + optional: true, + }, + timezoneId: { + type: "integer", + label: "Timezone ID", + description: "The timezone ID for the person", + optional: true, + }, + calendarStartsOnSunday: { + type: "string", + label: "Calendar Starts On Sunday", + description: "Whether the calendar starts on Sunday", + optional: true, + }, + lengthOfDay: { + type: "integer", + label: "Length of Day", + description: "The length of day in hours", + optional: true, + }, + workingHours: { + type: "object", + label: "Working Hours", + description: "Object containing working hours information. . [See the documentation](https://apidocs.teamwork.com/docs/teamwork/v1/people/post-people-json) for more information.", + optional: true, + }, + changeForEveryone: { + type: "boolean", + label: "Change For Everyone", + description: "Whether changes apply to everyone", + optional: true, + }, + administrator: { + type: "boolean", + label: "Administrator", + description: "Whether the person is an administrator", + optional: true, + }, + canAddProjects: { + type: "boolean", + label: "Can Add Projects", + description: "Whether the person can add projects", + optional: true, + }, + canManagePeople: { + type: "boolean", + label: "Can Manage People", + description: "Whether the person can manage people", + optional: true, + }, + autoGiveProjectAccess: { + type: "boolean", + label: "Auto Give Project Access", + description: "Whether to automatically give the person access to new projects", + optional: true, + }, + canAccessCalendar: { + type: "boolean", + label: "Can Access Calendar", + description: "Whether the person can access the calendar", + optional: true, + }, + canAccessTemplates: { + type: "boolean", + label: "Can Access Templates", + description: "Whether the person can access templates", + optional: true, + }, + canAccessPortfolio: { + type: "boolean", + label: "Can Access Portfolio", + description: "Whether the person can access the portfolio", + optional: true, + }, + canManageCustomFields: { + type: "boolean", + label: "Can Manage Custom Fields", + description: "Whether the person can manage custom fields", + optional: true, + }, + canManagePortfolio: { + type: "boolean", + label: "Can Manage Portfolio", + description: "Whether the person can manage the portfolio", + optional: true, + }, + canManageProjectTemplates: { + type: "boolean", + label: "Can Manage Project Templates", + description: "Whether the person can manage project templates", + optional: true, + }, + canViewProjectTemplates: { + type: "boolean", + label: "Can View Project Templates", + description: "Whether the person can view project templates", + optional: true, + }, + notifyOnTaskComplete: { + type: "boolean", + label: "Notify On Task Complete", + description: "Whether to notify when tasks are completed", + optional: true, + }, + notifyOnAddedAsFollower: { + type: "boolean", + label: "Notify On Added As Follower", + description: "Whether to notify when added as a follower", + optional: true, + }, + notifyOnStatusUpdate: { + type: "boolean", + label: "Notify On Status Update", + description: "Whether to notify on status updates", + optional: true, + }, + textFormat: { + type: "string", + label: "Text Format", + description: "The text format preference", + optional: true, + }, + useShorthandDurations: { + type: "boolean", + label: "Use Shorthand Durations", + description: "Whether to use shorthand durations", + optional: true, + }, + userReceiveNotifyWarnings: { + type: "boolean", + label: "User Receive Notify Warnings", + description: "Whether the user receives notification warnings", + optional: true, + }, + userReceiveMyNotificationsOnly: { + type: "boolean", + label: "User Receive My Notifications Only", + description: "Whether the user receives only their own notifications", + optional: true, + }, + receiveDailyReports: { + type: "boolean", + label: "Receive Daily Reports", + description: "Whether the person should receive daily reports", + optional: true, + }, + receiveDailyReportsAtWeekend: { + type: "boolean", + label: "Receive Daily Reports At Weekend", + description: "Whether to receive daily reports on weekends", + optional: true, + }, + receiveDailyReportsIfEmpty: { + type: "boolean", + label: "Receive Daily Reports If Empty", + description: "Whether to receive daily reports even if empty", + optional: true, + }, + soundAlertsEnabled: { + type: "boolean", + label: "Sound Alerts Enabled", + description: "Whether sound alerts are enabled", + optional: true, + }, + dailyReportSort: { + type: "string", + label: "Daily Report Sort", + description: "The sort order for daily reports", + optional: true, + }, + receiveDailyReportsAtTime: { + type: "string", + label: "Receive Daily Reports At Time", + description: "The time to receive daily reports", + optional: true, + }, + dailyReportEventsType: { + type: "string", + label: "Daily Report Events Type", + description: "The type of events for daily reports", + optional: true, + }, + dailyReportDaysFilter: { + type: "integer", + label: "Daily Report Days Filter", + description: "The days filter for daily reports", + optional: true, + }, + avatarPendingFileRef: { + type: "string", + label: "Avatar Pending File Ref", + description: "Reference to pending avatar file", + optional: true, + }, + removeAvatar: { + type: "boolean", + label: "Remove Avatar", + description: "Whether to remove the avatar", + optional: true, + }, + allowEmailNotifications: { + type: "boolean", + label: "Allow Email Notifications", + description: "Whether to allow email notifications", + optional: true, + }, + userType: { + type: "string", + label: "User Type", + description: "The type of user (account, collaborator, contact)", + optional: true, + options: [ + { + label: "Account", + value: "account", + }, + { + label: "Collaborator", + value: "collaborator", + }, + { + label: "Contact", + value: "contact", + }, + ], + }, + privateNotes: { + type: "string", + label: "Private Notes", + description: "Private notes about the person", + optional: true, + }, + getUserDetails: { + type: "boolean", + label: "Get User Details", + description: "Whether to return user details in the response", + optional: true, + }, + }, + async run({ $ }) { + const data = { + "email-address": this.emailAddress, + "first-name": this.firstName, + "last-name": this.lastName, + "company-id": this.companyId, + "sendInvite": this.sendInvite, + "title": this.title, + "phone-number-office": this.phoneNumberOffice, + "phone-number-office-ext": this.phoneNumberOfficeExt, + "phone-number-mobile-countrycode": this.phoneNumberMobileCountrycode, + "phone-number-mobile-prefix": this.phoneNumberMobilePrefix, + "phone-number-mobile": this.phoneNumberMobile, + "phone-number-home": this.phoneNumberHome, + "phone-number-fax": this.phoneNumberFax, + "email-alt-1": this.emailAlt1, + "email-alt-2": this.emailAlt2, + "email-alt-3": this.emailAlt3, + "address": parseObject(this.address), + "profile": this.profile, + "userTwitterName": this.userTwitterName, + "userLinkedin": this.userLinkedin, + "userFacebook": this.userFacebook, + "userWebsite": this.userWebsite, + "im-service": this.imService, + "im-handle": this.imHandle, + "language": this.language, + "dateFormatId": this.dateFormatId, + "timeFormatId": this.timeFormatId, + "timezoneId": this.timezoneId, + "calendarStartsOnSunday": this.calendarStartsOnSunday, + "lengthOfDay": this.lengthOfDay, + "workingHours": parseObject(this.workingHours), + "changeForEveryone": this.changeForEveryone, + "administrator": this.administrator, + "canAddProjects": this.canAddProjects, + "canManagePeople": this.canManagePeople, + "autoGiveProjectAccess": this.autoGiveProjectAccess, + "canAccessCalendar": this.canAccessCalendar, + "canAccessTemplates": this.canAccessTemplates, + "canAccessPortfolio": this.canAccessPortfolio, + "canManageCustomFields": this.canManageCustomFields, + "canManagePortfolio": this.canManagePortfolio, + "canManageProjectTemplates": this.canManageProjectTemplates, + "canViewProjectTemplates": this.canViewProjectTemplates, + "notifyOnTaskComplete": this.notifyOnTaskComplete, + "notify-on-added-as-follower": this.notifyOnAddedAsFollower, + "notify-on-status-update": this.notifyOnStatusUpdate, + "textFormat": this.textFormat, + "useShorthandDurations": this.useShorthandDurations, + "userReceiveNotifyWarnings": this.userReceiveNotifyWarnings, + "userReceiveMyNotificationsOnly": this.userReceiveMyNotificationsOnly, + "receiveDailyReports": this.receiveDailyReports, + "receiveDailyReportsAtWeekend": this.receiveDailyReportsAtWeekend, + "receiveDailyReportsIfEmpty": this.receiveDailyReportsIfEmpty, + "soundAlertsEnabled": this.soundAlertsEnabled, + "dailyReportSort": this.dailyReportSort, + "receiveDailyReportsAtTime": this.receiveDailyReportsAtTime, + "dailyReportEventsType": this.dailyReportEventsType, + "dailyReportDaysFilter": this.dailyReportDaysFilter, + "avatarPendingFileRef": this.avatarPendingFileRef, + "removeAvatar": this.removeAvatar, + "user-type": this.userType, + "privateNotes": this.privateNotes, + "getUserDetails": this.getUserDetails, + }; + const res = await this.app.updatePerson(this.peopleId, data, $); + $.export("$summary", `Updated user with ID: ${this.peopleId}`); + return res; + }, +}; diff --git a/components/teamwork/common/utils.mjs b/components/teamwork/common/utils.mjs new file mode 100644 index 0000000000000..9fdc004c18f32 --- /dev/null +++ b/components/teamwork/common/utils.mjs @@ -0,0 +1,25 @@ +export const parseObject = (obj) => { + if (!obj) { + return undefined; + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + if (Array.isArray(obj)) { + return obj.map(parseObject); + } + if (typeof obj === "object") { + return Object.fromEntries(Object.entries(obj).map(([ + key, + value, + ]) => [ + key, + parseObject(value), + ])); + } + return obj; +}; diff --git a/components/teamwork/package.json b/components/teamwork/package.json index 8977c173a9952..e7199ecbec322 100644 --- a/components/teamwork/package.json +++ b/components/teamwork/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/teamwork", - "version": "0.0.2", + "version": "0.1.0", "description": "Pipedream TeamWork Components", "main": "teamwork.app.mjs", "keywords": [ @@ -13,8 +13,7 @@ "access": "public" }, "dependencies": { - "@pipedream/platform": "^1.1.1", - "crypto": "^1.0.1", + "@pipedream/platform": "^3.1.0", "uuid": "^9.0.0" } } diff --git a/components/teamwork/sources/common/common-sources.mjs b/components/teamwork/sources/common/common-sources.mjs index 7b9a85f83e6c5..4387791be10a4 100644 --- a/components/teamwork/sources/common/common-sources.mjs +++ b/components/teamwork/sources/common/common-sources.mjs @@ -27,6 +27,9 @@ export default { _getEventName() { throw new Error("_getEventName() is not implemented"); }, + generateMeta() { + throw new Error("generateMeta() is not implemented"); + }, _generateWebhookToken() { return uuidv4(); }, @@ -62,4 +65,9 @@ export default { } }, }, + async run(event) { + this._checkHmac(event.bodyRaw, event.headers["x-projects-signature"]); + const meta = this.generateMeta(event.body); + this.$emit(event.body, meta); + }, }; diff --git a/components/teamwork/sources/new-task/new-task.mjs b/components/teamwork/sources/new-task/new-task.mjs index a3a66b7d39b15..4cc7cf840f2b7 100644 --- a/components/teamwork/sources/new-task/new-task.mjs +++ b/components/teamwork/sources/new-task/new-task.mjs @@ -5,21 +5,20 @@ export default { dedupe: "unique", type: "source", key: "teamwork-new-task", - name: "New Task", + name: "New Task (Instant)", description: "Emit new event when a new task is created", - version: "0.0.1", + version: "0.0.2", methods: { ...common.methods, _getEventName() { return "TASK.CREATED"; }, - }, - async run(event) { - this._checkHmac(event.bodyRaw, event.headers["x-projects-signature"]); - this.$emit(event.body, { - id: event.body["Task.ID"], - summary: event.body["Task.Name"], - ts: event.body["Task.DateCreated"], - }); + generateMeta(body) { + return { + id: body["Task.ID"], + summary: body["Task.Name"], + ts: body["Task.DateCreated"], + }; + }, }, }; diff --git a/components/teamwork/sources/new-user-created/new-user-created.mjs b/components/teamwork/sources/new-user-created/new-user-created.mjs new file mode 100644 index 0000000000000..94417f090127d --- /dev/null +++ b/components/teamwork/sources/new-user-created/new-user-created.mjs @@ -0,0 +1,24 @@ +import common from "../common/common-sources.mjs"; + +export default { + ...common, + key: "teamwork-new-user-created", + name: "New User Created (Instant)", + description: "Emit new event when a new user is created", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + _getEventName() { + return "USER.CREATED"; + }, + generateMeta(body) { + return { + id: body["User.ID"], + summary: body["User.FirstName"] + " " + body["User.LastName"], + ts: Date.parse(body["User.DateCreated"]), + }; + }, + }, +}; diff --git a/components/teamwork/sources/task-deleted/task-deleted.mjs b/components/teamwork/sources/task-deleted/task-deleted.mjs index 839d5cf021dca..83d43fa8aaa2b 100644 --- a/components/teamwork/sources/task-deleted/task-deleted.mjs +++ b/components/teamwork/sources/task-deleted/task-deleted.mjs @@ -5,21 +5,20 @@ export default { dedupe: "unique", type: "source", key: "teamwork-task-deleted", - name: "New Task Deleted", + name: "New Task Deleted (Instant)", description: "Emit new event when a new task is deleted", - version: "0.0.1", + version: "0.0.2", methods: { ...common.methods, _getEventName() { return "TASK.DELETED"; }, - }, - async run(event) { - this._checkHmac(event.bodyRaw, event.headers["x-projects-signature"]); - this.$emit(event.body, { - id: event.body.ID, - summary: `${event.body.ID} deleted by ${event.body["EventCreator.FirstName"]} ${event.body["EventCreator.LastName"]}`, - ts: Date.now(), - }); + generateMeta(body) { + return { + id: body.ID, + summary: `${body.ID} deleted by ${body["EventCreator.FirstName"]} ${body["EventCreator.LastName"]}`, + ts: Date.now(), + }; + }, }, }; diff --git a/components/teamwork/sources/task-updated/task-updated.mjs b/components/teamwork/sources/task-updated/task-updated.mjs index 66c14f1864b9a..4d581e20d1ef0 100644 --- a/components/teamwork/sources/task-updated/task-updated.mjs +++ b/components/teamwork/sources/task-updated/task-updated.mjs @@ -4,21 +4,20 @@ export default { ...common, type: "source", key: "teamwork-task-updated", - name: "New Task Updated", + name: "New Task Updated (Instant)", description: "Emit new event when a new task is updated", - version: "0.0.1", + version: "0.0.2", methods: { ...common.methods, _getEventName() { return "TASK.UPDATED"; }, - }, - async run(event) { - this._checkHmac(event.bodyRaw, event.headers["x-projects-signature"]); - this.$emit(event.body, { - id: event.body["Task.ID"], - summary: event.body["Task.Name"], - ts: event.body["Task.DateCreated"], - }); + generateMeta(body) { + return { + id: body["Task.ID"], + summary: body["Task.Name"], + ts: body["Task.DateCreated"], + }; + }, }, }; diff --git a/components/teamwork/sources/user-updated/user-updated.mjs b/components/teamwork/sources/user-updated/user-updated.mjs new file mode 100644 index 0000000000000..c0c86faafe420 --- /dev/null +++ b/components/teamwork/sources/user-updated/user-updated.mjs @@ -0,0 +1,25 @@ +import common from "../common/common-sources.mjs"; + +export default { + ...common, + key: "teamwork-user-updated", + name: "User Updated (Instant)", + description: "Emit new event when a user is updated", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + _getEventName() { + return "USER.UPDATED"; + }, + generateMeta(body) { + const ts = Date.parse(body["User.DateCreated"]); + return { + id: `${body["User.ID"]}-${ts}`, + summary: body["User.FirstName"] + " " + body["User.LastName"], + ts, + }; + }, + }, +}; diff --git a/components/teamwork/teamwork.app.mjs b/components/teamwork/teamwork.app.mjs index dd447cff30ae8..542a68df3ec29 100644 --- a/components/teamwork/teamwork.app.mjs +++ b/components/teamwork/teamwork.app.mjs @@ -76,6 +76,19 @@ export default { })); }, }, + companyId: { + type: "string", + label: "Company ID", + description: "ID of the company to list tasks from", + optional: true, + async options({ page }) { + const companies = await this.listCompanies(page + 1); + return companies.map((item) => ({ + label: item.name, + value: item.id, + })); + }, + }, content: { type: "string", label: "Content", @@ -157,16 +170,52 @@ export default { })); return res?.tasklists || []; }, - async listPeople(page, ctx = this) { + async getPerson(personId, ctx = this) { + const res = await axios(ctx, this._getAxiosParams({ + method: "GET", + path: `people/${personId}.json`, + })); + return res?.person || {}; + }, + async listPeople(page, ctx = this, params = {}) { const res = await axios(ctx, this._getAxiosParams({ method: "GET", path: "people.json", params: { page, + ...params, }, })); return res?.people || []; }, + async createPerson(data, ctx = this) { + return axios(ctx, this._getAxiosParams({ + method: "POST", + path: "people.json", + data: { + person: data, + }, + })); + }, + async updatePerson(personId, data, ctx = this) { + return axios(ctx, this._getAxiosParams({ + method: "PUT", + path: `people/${personId}.json`, + data: { + person: data, + }, + })); + }, + async listCompanies(page, ctx = this) { + const res = await axios(ctx, this._getAxiosParams({ + method: "GET", + path: "companies.json", + params: { + page, + }, + })); + return res?.companies || []; + }, async listColumns(projectId, page, ctx = this) { const res = await axios(ctx, this._getAxiosParams({ method: "GET", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 26403d39f965a..0aaf8c2940c40 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13594,11 +13594,8 @@ importers: components/teamwork: dependencies: '@pipedream/platform': - specifier: ^1.1.1 - version: 1.6.6 - crypto: - specifier: ^1.0.1 - version: 1.0.1 + specifier: ^3.1.0 + version: 3.1.0 uuid: specifier: ^9.0.0 version: 9.0.1