diff --git a/components/brillium/actions/list-assessments/list-assessments.mjs b/components/brillium/actions/list-assessments/list-assessments.mjs new file mode 100644 index 0000000000000..45e2fd37579d0 --- /dev/null +++ b/components/brillium/actions/list-assessments/list-assessments.mjs @@ -0,0 +1,50 @@ +import brillium from "../../brillium.app.mjs"; + +export default { + key: "brillium-list-assessments", + name: "List Assessments", + description: "Retrieve all Assessments for a Brillium account. [See the documentation](https://support.brillium.com/en-us/knowledgebase/article/KA-01063)", + version: "0.0.1", + type: "action", + props: { + brillium, + accountId: { + propDefinition: [ + brillium, + "accountId", + ], + }, + page: { + propDefinition: [ + brillium, + "page", + ], + }, + pageSize: { + propDefinition: [ + brillium, + "pageSize", + ], + }, + }, + async run({ $ }) { + try { + const { Assessments: assessments } = await this.brillium.listAssessments({ + $, + accountId: this.accountId, + params: { + page: this.page, + pagesize: this.pageSize, + }, + }); + if (assessments?.length) { + $.export("$summary", `Successfully retrieved ${assessments.length} assessment${assessments.length === 1 + ? "" + : "s"}`); + } + return assessments; + } catch { + $.export("$summary", "No Assessments found"); + } + }, +}; diff --git a/components/brillium/actions/list-questions/list-questions.mjs b/components/brillium/actions/list-questions/list-questions.mjs new file mode 100644 index 0000000000000..cd2e6d0a3e067 --- /dev/null +++ b/components/brillium/actions/list-questions/list-questions.mjs @@ -0,0 +1,76 @@ +import brillium from "../../brillium.app.mjs"; + +export default { + key: "brillium-list-questions", + name: "List Questions", + description: "Retrieve all Questions for an Assessment. [See the documentation](https://support.brillium.com/en-us/knowledgebase/article/KA-01071)", + version: "0.0.1", + type: "action", + props: { + brillium, + accountId: { + propDefinition: [ + brillium, + "accountId", + ], + }, + assessmentId: { + propDefinition: [ + brillium, + "assessmentId", + (c) => ({ + accountId: c.accountId, + }), + ], + }, + topicId: { + propDefinition: [ + brillium, + "topicId", + (c) => ({ + assessmentId: c.assessmentId, + }), + ], + optional: true, + }, + page: { + propDefinition: [ + brillium, + "page", + ], + }, + pageSize: { + propDefinition: [ + brillium, + "pageSize", + ], + }, + }, + async run({ $ }) { + try { + const params = { + page: this.page, + pagesize: this.pageSize, + }; + const { Questions: questions } = this.topicId + ? await this.brillium.listTopicQuestions({ + $, + topicId: this.topicId, + params, + }) + : await this.brillium.listQuestions({ + $, + assessmentId: this.assessmentId, + params, + }); + if (questions?.length) { + $.export("$summary", `Successfully retrieved ${questions.length} question${questions.length === 1 + ? "" + : "s"}`); + } + return questions; + } catch { + $.export("$summary", "No Questions found"); + } + }, +}; diff --git a/components/brillium/actions/list-respondent-results/list-respondent-results.mjs b/components/brillium/actions/list-respondent-results/list-respondent-results.mjs new file mode 100644 index 0000000000000..15b47c2c62d67 --- /dev/null +++ b/components/brillium/actions/list-respondent-results/list-respondent-results.mjs @@ -0,0 +1,59 @@ +import brillium from "../../brillium.app.mjs"; + +export default { + key: "brillium-list-respondent-results", + name: "List Respondent Results", + description: "Retrieves results for a respondent. [See the documentation](https://support.brillium.com/en-us/knowledgebase/article/KA-01073)", + version: "0.0.1", + type: "action", + props: { + brillium, + accountId: { + propDefinition: [ + brillium, + "accountId", + ], + }, + respondentId: { + propDefinition: [ + brillium, + "respondentId", + (c) => ({ + accountId: c.accountId, + }), + ], + }, + page: { + propDefinition: [ + brillium, + "page", + ], + }, + pageSize: { + propDefinition: [ + brillium, + "pageSize", + ], + }, + }, + async run({ $ }) { + try { + const { Results: results } = await this.brillium.listRespondentResults({ + $, + respondentId: this.respondentId, + params: { + page: this.page, + pagesize: this.pageSize, + }, + }); + if (results?.length) { + $.export("$summary", `Successfully retrieved ${results.length} result${results.length === 1 + ? "" + : "s"}`); + } + return results; + } catch { + $.export("$summary", "No Results found"); + } + }, +}; diff --git a/components/brillium/actions/list-respondents/list-respondents.mjs b/components/brillium/actions/list-respondents/list-respondents.mjs new file mode 100644 index 0000000000000..0b41db7055ba6 --- /dev/null +++ b/components/brillium/actions/list-respondents/list-respondents.mjs @@ -0,0 +1,67 @@ +import brillium from "../../brillium.app.mjs"; + +export default { + key: "brillium-list-respondents", + name: "List Respondents", + description: "Retrieve all Respondents for a Brillium account. [See the documentation](https://support.brillium.com/en-us/knowledgebase/article/KA-01061)", + version: "0.0.1", + type: "action", + props: { + brillium, + accountId: { + propDefinition: [ + brillium, + "accountId", + ], + }, + assessmentId: { + propDefinition: [ + brillium, + "assessmentId", + (c) => ({ + accountId: c.accountId, + }), + ], + optional: true, + }, + page: { + propDefinition: [ + brillium, + "page", + ], + }, + pageSize: { + propDefinition: [ + brillium, + "pageSize", + ], + }, + }, + async run({ $ }) { + try { + const params = { + page: this.page, + pagesize: this.pageSize, + }; + const { Respondents: respondents } = this.assessmentId + ? await this.brillium.listAssessmentRespondents({ + $, + assessmentId: this.assessmentId, + params, + }) + : await this.brillium.listRespondents({ + $, + accountId: this.accountId, + params, + }); + if (respondents?.length) { + $.export("$summary", `Successfully retrieved ${respondents.length} respondent${respondents.length === 1 + ? "" + : "s"}`); + } + return respondents; + } catch { + $.export("$summary", "No Respondents found"); + } + }, +}; diff --git a/components/brillium/actions/list-topics/list-topics.mjs b/components/brillium/actions/list-topics/list-topics.mjs new file mode 100644 index 0000000000000..f9659f12913df --- /dev/null +++ b/components/brillium/actions/list-topics/list-topics.mjs @@ -0,0 +1,59 @@ +import brillium from "../../brillium.app.mjs"; + +export default { + key: "brillium-list-topics", + name: "List Topics", + description: "Retrieve all Topics for an Assessment. [See the documentation](https://support.brillium.com/en-us/knowledgebase/article/KA-01063)", + version: "0.0.1", + type: "action", + props: { + brillium, + accountId: { + propDefinition: [ + brillium, + "accountId", + ], + }, + assessmentId: { + propDefinition: [ + brillium, + "assessmentId", + (c) => ({ + accountId: c.accountId, + }), + ], + }, + page: { + propDefinition: [ + brillium, + "page", + ], + }, + pageSize: { + propDefinition: [ + brillium, + "pageSize", + ], + }, + }, + async run({ $ }) { + try { + const { QuestionGroups: topics } = await this.brillium.listTopics({ + $, + assessmentId: this.assessmentId, + params: { + page: this.page, + pagesize: this.pageSize, + }, + }); + if (topics?.length) { + $.export("$summary", `Successfully retrieved ${topics.length} topic${topics.length === 1 + ? "" + : "s"}`); + } + return topics; + } catch { + $.export("$summary", "No Topics found"); + } + }, +}; diff --git a/components/brillium/brillium.app.mjs b/components/brillium/brillium.app.mjs index 318c547227b06..cfc5d2ccf0bf7 100644 --- a/components/brillium/brillium.app.mjs +++ b/components/brillium/brillium.app.mjs @@ -1,11 +1,232 @@ +import { axios } from "@pipedream/platform"; +import { MAX_PAGE_LIMIT } from "./common/constants.mjs"; + export default { type: "app", app: "brillium", - propDefinitions: {}, + propDefinitions: { + accountId: { + type: "string", + label: "Account ID", + description: "The ID of the Workspace the assessment resides within", + async options({ page }) { + try { + const { Accounts: accounts } = await this.listAccounts({ + params: { + page: page + 1, + }, + }); + return accounts?.map(({ + Id: value, Name: label, + }) => ({ + value, + label: label === "N/A" + ? value + : label, + })) || []; + } catch { + return []; + } + }, + }, + assessmentId: { + type: "string", + label: "Assessment ID", + description: "The unique identifier for an assessment", + async options({ + page, accountId, + }) { + try { + const { Assessments: assessments } = await this.listAssessments({ + accountId, + params: { + page: page + 1, + }, + }); + return assessments?.map(({ + Id: value, Name: label, + }) => ({ + value, + label, + })) || []; + } catch { + return []; + } + }, + }, + topicId: { + type: "string", + label: "Topic ID", + description: "The unique identifier for a topic", + async options({ + page, assessmentId, + }) { + try { + const { QuestionGroups: topics } = await this.listTopics({ + assessmentId, + params: { + page: page + 1, + }, + }); + return topics?.map(({ + Id: value, Name: label, + }) => ({ + value, + label, + })) || []; + } catch { + return []; + } + }, + }, + respondentId: { + type: "string", + label: "Respondent ID", + description: "The unique identifier for a respondent", + async options({ + page, accountId, + }) { + try { + const { Respondents: respondents } = await this.listRespondents({ + accountId, + params: { + page: page + 1, + }, + }); + return respondents?.map(({ + Id: value, FirstName: firstName, LastName: lastName, + }) => ({ + value, + label: (`${firstName} ${lastName}`).trim(), + })) || []; + } catch { + return []; + } + }, + }, + page: { + type: "integer", + label: "Page", + description: "The page of results to return. Default is `1`", + default: 1, + optional: true, + }, + pageSize: { + type: "integer", + label: "Page Size", + description: "The number of results to return. Must be between 1 - 1000. Default is `1000`", + default: MAX_PAGE_LIMIT, + optional: true, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return `${this.$auth.api_url}/api`; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: `${this._baseUrl()}${path}`, + auth: { + username: "ASSESSMENTS-API", + password: `${this.$auth.api_password}${this.$auth.security_token}`, + }, + ...opts, + }); + }, + listAccounts(opts = {}) { + return this._makeRequest({ + path: "/Accounts", + ...opts, + }); + }, + listAssessments({ + accountId, ...opts + }) { + return this._makeRequest({ + path: `/Accounts/${accountId}/Assessments`, + ...opts, + }); + }, + listRespondents({ + accountId, ...opts + }) { + return this._makeRequest({ + path: `/Accounts/${accountId}/Respondents`, + ...opts, + }); + }, + listAssessmentRespondents({ + assessmentId, ...opts + }) { + return this._makeRequest({ + path: `/Assessments/${assessmentId}/Respondents`, + ...opts, + }); + }, + listQuestions({ + assessmentId, ...opts + }) { + return this._makeRequest({ + path: `/Assessments/${assessmentId}/Questions`, + ...opts, + }); + }, + listTopics({ + assessmentId, ...opts + }) { + return this._makeRequest({ + path: `/Assessments/${assessmentId}/QuestionGroups`, + ...opts, + }); + }, + listTopicQuestions({ + topicId, ...opts + }) { + return this._makeRequest({ + path: `/QuestionGroups/${topicId}/Questions`, + ...opts, + }); + }, + listRespondentResults({ + respondentId, ...opts + }) { + return this._makeRequest({ + path: `/Respondents/${respondentId}/Results`, + ...opts, + }); + }, + async *paginate({ + resourceFn, + args, + resourceKey, + max, + }) { + args = { + ...args, + params: { + ...args?.params, + page: 1, + pagesize: MAX_PAGE_LIMIT, + }, + }; + let hasMore, count = 0; + do { + const response = await resourceFn(args); + const items = response[resourceKey]; + if (!items?.length) { + return; + } + for (const item of items) { + yield item; + if (max && ++count >= max) { + return; + } + } + hasMore = response.HasMore; + args.params.page++; + } while (hasMore); }, }, }; diff --git a/components/brillium/common/constants.mjs b/components/brillium/common/constants.mjs new file mode 100644 index 0000000000000..f93f187dbb8b6 --- /dev/null +++ b/components/brillium/common/constants.mjs @@ -0,0 +1,7 @@ +const DEFAULT_PAGE_LIMIT = 20; +const MAX_PAGE_LIMIT = 1000; + +export { + DEFAULT_PAGE_LIMIT, + MAX_PAGE_LIMIT, +}; diff --git a/components/brillium/package.json b/components/brillium/package.json index ccfe2c6bfaa58..f6ad255de7780 100644 --- a/components/brillium/package.json +++ b/components/brillium/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/brillium", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Brillium Components", "main": "brillium.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } } diff --git a/components/brillium/sources/common/base.mjs b/components/brillium/sources/common/base.mjs new file mode 100644 index 0000000000000..8297f86078cdc --- /dev/null +++ b/components/brillium/sources/common/base.mjs @@ -0,0 +1,96 @@ +import brillium from "../../brillium.app.mjs"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; + +export default { + props: { + brillium, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + accountId: { + propDefinition: [ + brillium, + "accountId", + ], + }, + }, + methods: { + _getLastTs() { + return this.db.get("lastTs") || 0; + }, + _setLastTs(lastTs) { + this.db.set("lastTs", lastTs); + }, + async processEvent(limit) { + const lastTs = this._getLastTs(); + let maxTs = lastTs; + + const resourceFn = this.getResourceFn(); + const args = this.getArgs(); + const resourceKey = this.getResourceKey(); + const tsField = this.getTsField(); + + const items = this.brillium.paginate({ + resourceFn, + args, + resourceKey, + }); + + let results = []; + try { + for await (const item of items) { + const ts = Date.parse(item[tsField]); + if (ts > lastTs) { + results.push(item); + maxTs = Math.max(maxTs, ts); + } + } + } catch (e) { + console.log(`${e.message}`); + return; + } + + if (!results.length) { + return; + } + + this._setLastTs(maxTs); + + if (limit) { + results = results.slice(-1 * limit); + } + + results.reverse().forEach((item) => { + const meta = this.generateMeta(item); + this.$emit(item, meta); + }); + }, + getResourceFn() { + throw new Error("getResourceFn is not implemented"); + }, + getArgs() { + throw new Error("getArgs is not implemented"); + }, + getResourceKey() { + throw new Error("getResourceKey is not implemented"); + }, + getTsField() { + throw new Error("getTsField is not implemented"); + }, + generateMeta() { + throw new Error("generateMeta is not implemented"); + }, + }, + hooks: { + async deploy() { + await this.processEvent(25); + }, + }, + async run() { + await this.processEvent(); + }, +}; diff --git a/components/brillium/sources/new-assessment-topic/new-assessment-topic.mjs b/components/brillium/sources/new-assessment-topic/new-assessment-topic.mjs new file mode 100644 index 0000000000000..d20209cd3b6b0 --- /dev/null +++ b/components/brillium/sources/new-assessment-topic/new-assessment-topic.mjs @@ -0,0 +1,47 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "brillium-new-assessment-topic", + name: "New Assessment Topic", + description: "Emit new event when a new topic is added to an assessment in Brillium. [See the documentation](https://support.brillium.com/en-us/knowledgebase/article/KA-01063)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ...common.props, + assessmentId: { + propDefinition: [ + common.props.brillium, + "assessmentId", + (c) => ({ + accountId: c.accountId, + }), + ], + }, + }, + methods: { + ...common.methods, + getResourceFn() { + return this.brillium.listTopics; + }, + getArgs() { + return { + assessmentId: this.assessmentId, + }; + }, + getResourceKey() { + return "QuestionGroups"; + }, + getTsField() { + return "DateCreated"; + }, + generateMeta(topic) { + return { + id: topic.Id, + summary: `New Topic: ${topic.Name}`, + ts: Date.parse(topic[this.getTsField()]), + }; + }, + }, +}; diff --git a/components/brillium/sources/new-assessment/new-assessment.mjs b/components/brillium/sources/new-assessment/new-assessment.mjs new file mode 100644 index 0000000000000..fbcc9413d0da6 --- /dev/null +++ b/components/brillium/sources/new-assessment/new-assessment.mjs @@ -0,0 +1,35 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "brillium-new-assessment", + name: "New Assessment Created", + description: "Emit new event when a new assessment is created in Brillium. [See the documentation](https://support.brillium.com/en-us/knowledgebase/article/KA-01063)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getResourceFn() { + return this.brillium.listAssessments; + }, + getArgs() { + return { + accountId: this.accountId, + }; + }, + getResourceKey() { + return "Assessments"; + }, + getTsField() { + return "DateCreated"; + }, + generateMeta(assessment) { + return { + id: assessment.Id, + summary: `New Assessment: ${assessment.Name}`, + ts: Date.parse(assessment[this.getTsField()]), + }; + }, + }, +}; diff --git a/components/brillium/sources/new-question-added/new-question-added.mjs b/components/brillium/sources/new-question-added/new-question-added.mjs new file mode 100644 index 0000000000000..69f36691d53a3 --- /dev/null +++ b/components/brillium/sources/new-question-added/new-question-added.mjs @@ -0,0 +1,63 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "brillium-new-question-added", + name: "New Question Added", + description: "Emit new event when a new question is added to an assessment in Brillium. [See the documentation](https://support.brillium.com/en-us/knowledgebase/article/KA-01071)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ...common.props, + assessmentId: { + propDefinition: [ + common.props.brillium, + "assessmentId", + (c) => ({ + accountId: c.accountId, + }), + ], + }, + topicId: { + propDefinition: [ + common.props.brillium, + "topicId", + (c) => ({ + assessmentId: c.assessmentId, + }), + ], + optional: true, + }, + }, + methods: { + ...common.methods, + getResourceFn() { + return this.topicId + ? this.brillium.listTopicQuestions + : this.brillium.listQuestions; + }, + getArgs() { + return this.topicId + ? { + topicId: this.topicId, + } + : { + assessmentId: this.assessmentId, + }; + }, + getResourceKey() { + return "Questions"; + }, + getTsField() { + return "Id"; + }, + generateMeta(question) { + return { + id: question.Id, + summary: `New Question with ID: ${question.Id}`, + ts: Date.now(), + }; + }, + }, +}; diff --git a/components/brillium/sources/new-respondent-results/new-respondent-results.mjs b/components/brillium/sources/new-respondent-results/new-respondent-results.mjs new file mode 100644 index 0000000000000..d4d5c6ce2c883 --- /dev/null +++ b/components/brillium/sources/new-respondent-results/new-respondent-results.mjs @@ -0,0 +1,47 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "brillium-new-respondent-results", + name: "New Respondent Results", + description: "Emit new event when new results are added for an existing respondent. [See the documentation](https://support.brillium.com/en-us/knowledgebase/article/KA-01073)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ...common.props, + respondentId: { + propDefinition: [ + common.props.brillium, + "respondentId", + (c) => ({ + accountId: c.accountId, + }), + ], + }, + }, + methods: { + ...common.methods, + getResourceFn() { + return this.brillium.listRespondentResults; + }, + getArgs() { + return { + respondentId: this.respondentId, + }; + }, + getResourceKey() { + return "Results"; + }, + getTsField() { + return "DateAnswered"; + }, + generateMeta(result) { + return { + id: result.Id, + summary: `New Results with ID: ${result.Id}`, + ts: Date.parse(result[this.getTsField()]), + }; + }, + }, +}; diff --git a/components/brillium/sources/new-respondent/new-respondent.mjs b/components/brillium/sources/new-respondent/new-respondent.mjs new file mode 100644 index 0000000000000..0535362148bde --- /dev/null +++ b/components/brillium/sources/new-respondent/new-respondent.mjs @@ -0,0 +1,54 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "brillium-new-respondent", + name: "New Respondent", + description: "Emit new event when a new respondent completes an exam, test, quiz, or survey. [See the documentation](https://support.brillium.com/en-us/knowledgebase/article/KA-01061)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ...common.props, + assessmentId: { + propDefinition: [ + common.props.brillium, + "assessmentId", + (c) => ({ + accountId: c.accountId, + }), + ], + optional: true, + }, + }, + methods: { + ...common.methods, + getResourceFn() { + return this.assessmentId + ? this.brillium.listAssessmentRespondents + : this.brillium.listRespondents; + }, + getArgs() { + return this.assessmentId + ? { + assessmentId: this.assessmentId, + } + : { + accountId: this.accountId, + }; + }, + getResourceKey() { + return "Respondents"; + }, + getTsField() { + return "DateStarted"; + }, + generateMeta(respondent) { + return { + id: respondent.Id, + summary: `New Respondent: ${respondent.FirstName} ${respondent.LastName}`, + ts: Date.parse(respondent[this.getTsField()]), + }; + }, + }, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4949a3b25dc09..05bdbe8a95b2c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1752,7 +1752,11 @@ importers: specifier: ^6.11.2 version: 6.13.1 - components/brillium: {} + components/brillium: + dependencies: + '@pipedream/platform': + specifier: ^3.0.3 + version: 3.0.3 components/brosix: {} @@ -8168,8 +8172,7 @@ importers: specifier: ^1.1.1 version: 1.6.6 - components/needle: - specifiers: {} + components/needle: {} components/neetoinvoice: dependencies: