chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:34:48 +08:00
commit 77bb5bf71f
3762 changed files with 353249 additions and 0 deletions
@@ -0,0 +1,18 @@
import { addCommentToTaskInputSchema } from '../misc/custom-schemas'
import type { IntegrationProps } from '../misc/types'
import { getClient } from '../utils'
export const addCommentToTask: IntegrationProps['actions']['addCommentToTask'] = async ({ ctx, input, logger }) => {
const validatedInput = addCommentToTaskInputSchema.parse(input)
const asanaClient = getClient(ctx.configuration)
let response
try {
response = await asanaClient.addCommentToTask(validatedInput.taskId, validatedInput.comment)
logger.forBot().info(`Successful - Add Comment to Task - ${response.text}`)
} catch (error) {
logger.forBot().debug(`'Add Comment to Task' exception ${JSON.stringify(error)}`)
response = {}
}
return { text: response.text || '' }
}
@@ -0,0 +1,28 @@
import { createTaskInputSchema } from '../misc/custom-schemas'
import type { IntegrationProps } from '../misc/types'
import { getClient } from '../utils'
export const createTask: IntegrationProps['actions']['createTask'] = async ({ ctx, input, logger }) => {
const validatedInput = createTaskInputSchema.parse(input)
const asanaClient = getClient(ctx.configuration)
const task = {
workspace: ctx.configuration.workspaceGid,
name: validatedInput.name,
notes: validatedInput.notes || undefined,
assignee: validatedInput.assignee || undefined,
projects: validatedInput.projects?.split(',').map((project) => project.trim()) || undefined,
parent: validatedInput.parent || undefined,
due_on: validatedInput.due_on || validatedInput.start_on || undefined,
start_on: validatedInput.start_on || undefined,
}
let response
try {
response = await asanaClient.createTask(task)
logger.forBot().info(`Successful - Create Task - ${response.permalink_url}`)
} catch (error) {
logger.forBot().debug(`'Create Task' exception ${JSON.stringify(error)}`)
response = {}
}
return { permalink_url: response.permalink_url || '' }
}
@@ -0,0 +1,18 @@
import { findUserInputSchema } from '../misc/custom-schemas'
import type { IntegrationProps } from '../misc/types'
import { getClient } from '../utils'
export const findUser: IntegrationProps['actions']['findUser'] = async ({ ctx, input, logger }) => {
const validatedInput = findUserInputSchema.parse(input)
const asanaClient = getClient(ctx.configuration)
let response
try {
response = await asanaClient.findUser(validatedInput.userEmail)
logger.forBot().info(`Successful - Find User - ${response.name}`)
} catch (error) {
logger.forBot().debug(`'Find User' exception ${JSON.stringify(error)}`)
response = {}
}
return response
}
+6
View File
@@ -0,0 +1,6 @@
import { addCommentToTask } from './add-comment-to-task'
import { createTask } from './create-task'
import { findUser } from './find-user'
import { updateTask } from './update-task'
export default { createTask, updateTask, findUser, addCommentToTask }
@@ -0,0 +1,26 @@
import { updateTaskInputSchema } from '../misc/custom-schemas'
import type { IntegrationProps } from '../misc/types'
import { getClient } from '../utils'
export const updateTask: IntegrationProps['actions']['updateTask'] = async ({ ctx, input, logger }) => {
const validatedInput = updateTaskInputSchema.parse(input)
const asanaClient = getClient(ctx.configuration)
const task = {
name: validatedInput.name,
notes: validatedInput.notes || undefined,
assignee: validatedInput.assignee || undefined,
due_on: validatedInput.due_on || validatedInput.start_on || undefined,
start_on: validatedInput.start_on || undefined,
completed: validatedInput.completed === 'true' ? true : undefined,
}
let response
try {
response = await asanaClient.updateTask(validatedInput.taskId, task)
logger.forBot().info(`Successful - Update Task - ${response.permalink_url}`)
} catch (error) {
logger.forBot().debug(`'Update Task' exception ${JSON.stringify(error)}`)
response = {}
}
return { permalink_url: response.permalink_url || '' }
}
+39
View File
@@ -0,0 +1,39 @@
import * as asana from 'asana'
export class AsanaApi {
private _client: asana.Client
public constructor(apiToken: string) {
this._client = asana.Client.create({
defaultHeaders: {
'Asana-Enable': 'new_goal_memberships,new_user_task_lists',
},
}).useAccessToken(apiToken)
}
public async createTask(
task: asana.resources.Tasks.CreateParams & { workspace: string }
): Promise<asana.resources.Tasks.Type> {
return await this._client.tasks.create(task)
}
public async updateTask(
taskId: string,
task: asana.resources.Tasks.UpdateParams
): Promise<asana.resources.Tasks.Type> {
return await this._client.tasks.update(taskId, task)
}
public async addCommentToTask(taskId: string, comment: string): Promise<asana.resources.Stories.Type> {
return await this._client.tasks.addComment(taskId, { text: comment })
}
public async findUser(userEmail: string): Promise<asana.resources.Users.Type> {
return await this._client.users.findById(userEmail)
}
public async findAllUsers(workspace: string): Promise<asana.resources.Users.Type[]> {
const users = await this._client.users.findAll({ workspace })
return users.data as asana.resources.Users.Type[]
}
}
+1
View File
@@ -0,0 +1 @@
export const INTEGRATION_NAME = 'asana'
@@ -0,0 +1,65 @@
import * as sdk from '@botpress/sdk'
import {
createTaskInputSchema,
createTaskOutputSchema,
updateTaskInputSchema,
updateTaskOutputSchema,
findUserInputSchema,
findUserOutputSchema,
addCommentToTaskInputSchema,
addCommentToTaskOutputSchema,
} from '../misc/custom-schemas'
type SdkActions = NonNullable<sdk.IntegrationDefinitionProps['actions']>
type SdkAction = SdkActions[string]
const createTask = {
title: 'Create Task',
description: 'Create Task',
input: {
schema: createTaskInputSchema,
},
output: {
schema: createTaskOutputSchema,
},
} satisfies SdkAction
const updateTask = {
title: 'Update Task',
description: 'Update Task by taskId',
input: {
schema: updateTaskInputSchema,
},
output: {
schema: updateTaskOutputSchema,
},
} satisfies SdkAction
const findUser = {
title: 'Find User',
description: 'Find User by userId',
input: {
schema: findUserInputSchema,
},
output: {
schema: findUserOutputSchema,
},
} satisfies SdkAction
const addCommentToTask = {
title: 'Add Comment to Task',
description: 'Add Comment to Task, by task ID',
input: {
schema: addCommentToTaskInputSchema,
},
output: {
schema: addCommentToTaskOutputSchema,
},
} satisfies SdkAction
export const actions = {
createTask,
updateTask,
findUser,
addCommentToTask,
} satisfies SdkActions
@@ -0,0 +1,13 @@
import { IntegrationDefinitionProps, messages } from '@botpress/sdk'
export const channels = {
channel: {
title: 'Channel',
description: 'The channel for Asana',
messages: {
...messages.defaults,
markdown: messages.markdown,
bloc: messages.markdownBloc,
},
},
} satisfies IntegrationDefinitionProps['channels']
@@ -0,0 +1,32 @@
import { z, IntegrationDefinitionProps } from '@botpress/sdk'
export { actions } from './actions'
export { channels } from './channels'
export const configuration = {
schema: z.object({
apiToken: z.string().min(1).title('API Token').describe('API Token'),
workspaceGid: z.string().min(1).title('Workspace Global ID').describe('Workspace Global ID'),
}),
} satisfies IntegrationDefinitionProps['configuration']
export const states = {
// voidStateOne: {
// type: 'integration',
// schema: z.object({
// dataField: z.string(),
// }),
// },
// voidStateTwo: {
// type: 'conversation',
// schema: z.object({
// otherDataField: z.string(),
// }),
// },
} satisfies IntegrationDefinitionProps['states']
export const user = {
tags: {
// id: {},
},
} satisfies IntegrationDefinitionProps['user']
+14
View File
@@ -0,0 +1,14 @@
import { reporting } from '@botpress/sdk-addons'
import actions from './actions'
import { register, unregister, channels, handler } from './setup'
import * as bp from '.botpress'
const integration = new bp.Integration({
register,
unregister,
actions,
channels,
handler,
})
export default reporting.wrapIntegration(integration)
@@ -0,0 +1,95 @@
import { z } from '@botpress/sdk'
import { photoSchema, workspaceSchema } from './sub-schemas'
export const createTaskInputSchema = z.object({
name: z.string().describe('The name of the task (e.g. "My Test Task")').title('Name'),
notes: z
.string()
.optional()
.describe('The description of the task (Optional) (e.g. "This is my other task created using the Asana API")')
.title('Notes'),
assignee: z
.string()
.optional()
.default('me')
.describe(
'The ID of the user who will be assigned to the task or "me" to assign to the current user (Optional) (e.g. "1215207682932839") (Default: "me")'
)
.title('Assignee'),
projects: z
.string()
.optional()
.describe(
'The project IDs should be strings separated by commas (Optional) (e.g. "1205199808673678, 1215207282932839").'
)
.title('Projects'),
parent: z
.string()
.optional()
.describe('The ID of the parent task (Optional) (e.g. "1205206556256028")')
.title('Parent'),
start_on: z
.string()
.optional()
.describe('The start date of the task in YYYY-MM-DD format (Optional) (e.g. "2023-08-13")')
.title('Start On'),
due_on: z
.string()
.optional()
.describe('The due date of the task without a specific time in YYYY-MM-DD format (Optional) (e.g. "2023-08-15")')
.title('Due On'),
})
export const taskOutputSchema = z.object({
permalink_url: z.string().describe('The permalink url').title('Permalink Url'),
})
export const createTaskOutputSchema = taskOutputSchema
export const updateTaskInputSchema = createTaskInputSchema
.omit({
projects: true,
parent: true,
})
.extend({
taskId: z.string().describe('Task ID to update').title('Task ID'),
name: z.string().optional().describe('The name of the task (Optional) (e.g. "My Test Task")').title('Name'),
assignee: z
.string()
.optional()
.describe(
'The ID of the user who will be assigned to the task or "me" to assign to the current user (Optional) (e.g. "1215207682932839")'
)
.title('Assignee'),
completed: z
.string()
.optional()
.describe(
'If the task is completed, enter "true" (without quotes), otherwise it will keep its previous status. (Optional)'
)
.title('Completed'),
})
export const updateTaskOutputSchema = taskOutputSchema
export const findUserInputSchema = z.object({
userEmail: z.string().describe('User Email (e.g. "mrsomebody@example.com")').title('User Email'),
})
export const findUserOutputSchema = z
.object({
gid: z.string().describe('The GID of the User').title('GID'),
name: z.string().describe('The name of the user').title('Name'),
email: z.string().describe('The email of the user').title('Email'),
photo: photoSchema.describe('The photo of the user').title('Photo'),
resource_type: z.string().describe('The resource type of the user').title('Resource Type'),
workspaces: z.array(workspaceSchema).describe('List of the workspaces').title('Workspaces'),
})
.partial()
export const addCommentToTaskInputSchema = z.object({
taskId: z.string().describe('Task ID to comment').title('Task ID'),
comment: z.string().describe('Content of the comment to be added').title('Comment'),
})
export const addCommentToTaskOutputSchema = z.object({
text: z.string().describe('The text of the comment').title('Text'),
})
@@ -0,0 +1,19 @@
import { z } from '@botpress/sdk'
const workspaceSchema = z.object({
gid: z.string().describe('The GID of the workspace').title('GID'),
name: z.string().describe('The name of the workspace').title('Name'),
resource_type: z.string().describe('The resource type of the workspace').title('Resource Type'),
})
const photoSchema = z
.object({
image_21x21: z.string().describe('An Image 21 by 21').title('Image 21x21'),
image_27x27: z.string().describe('An Image 27 by 27').title('Image 27x27'),
image_36x36: z.string().describe('An Image 36 by 36').title('Image 36x36'),
image_60x60: z.string().describe('An Image 60 by 60').title('Image 60x60'),
image_128x128: z.string().describe('An Image 128 by 128').title('Image 128x128'),
})
.nullable()
export { workspaceSchema, photoSchema }
+9
View File
@@ -0,0 +1,9 @@
import * as bp from '.botpress'
export type Configuration = bp.configuration.Configuration
export type IntegrationProps = bp.IntegrationProps
export type IntegrationCtx = bp.Context
export type RegisterFunction = IntegrationProps['register']
export type UnregisterFunction = IntegrationProps['unregister']
export type Channels = IntegrationProps['channels']
export type Handler = IntegrationProps['handler']
+50
View File
@@ -0,0 +1,50 @@
import type { Channels } from '../misc/types'
class NotImplementedError extends Error {
public constructor() {
super('Not implemented')
}
}
export const channels: Channels = {
channel: {
messages: {
text: async () => {
throw new NotImplementedError()
},
image: async () => {
throw new NotImplementedError()
},
markdown: async () => {
throw new NotImplementedError()
},
audio: async () => {
throw new NotImplementedError()
},
video: async () => {
throw new NotImplementedError()
},
file: async () => {
throw new NotImplementedError()
},
location: async () => {
throw new NotImplementedError()
},
carousel: async () => {
throw new NotImplementedError()
},
card: async () => {
throw new NotImplementedError()
},
choice: async () => {
throw new NotImplementedError()
},
dropdown: async () => {
throw new NotImplementedError()
},
bloc: async () => {
throw new NotImplementedError()
},
},
},
}
+11
View File
@@ -0,0 +1,11 @@
import type { Handler } from '../misc/types'
class NotImplementedError extends Error {
public constructor() {
super('Not implemented')
}
}
export const handler: Handler = async () => {
throw new NotImplementedError()
}
+4
View File
@@ -0,0 +1,4 @@
export { register } from './register'
export { unregister } from './unregister'
export { channels } from './channels'
export { handler } from './handler'
+8
View File
@@ -0,0 +1,8 @@
import type { RegisterFunction } from '../misc/types'
export const register: RegisterFunction = async () => {
/**
* This is called when an integration configuration is saved.
* You should use this handler to instanciate ressources in the external service and ensure that the configuration is valid.
*/
}
@@ -0,0 +1,8 @@
import type { UnregisterFunction } from '../misc/types'
export const unregister: UnregisterFunction = async () => {
/**
* This is called when a bot removes the integration.
* You should use this handler to instanciate ressources in the external service and ensure that the configuration is valid.
*/
}
+4
View File
@@ -0,0 +1,4 @@
import { AsanaApi } from '../client'
import type { Configuration } from '../misc/types'
export const getClient = (config: Configuration) => new AsanaApi(config.apiToken)