Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"extends": [
|
||||
"../../../../.eslintrc.base.json"
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"!**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx",
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# pieces-webling
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Building
|
||||
|
||||
Run `nx build pieces-webling` to build the library.
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "@activepieces/piece-webling",
|
||||
"version": "0.0.7"
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "pieces-webling",
|
||||
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/pieces/community/webling/src",
|
||||
"projectType": "library",
|
||||
"release": {
|
||||
"version": {
|
||||
"currentVersionResolver": "git-tag",
|
||||
"preserveLocalDependencyProtocols": false,
|
||||
"manifestRootsToUpdate": [
|
||||
"dist/{projectRoot}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"options": {
|
||||
"outputPath": "dist/packages/pieces/community/webling",
|
||||
"tsConfig": "packages/pieces/community/webling/tsconfig.lib.json",
|
||||
"packageJson": "packages/pieces/community/webling/package.json",
|
||||
"main": "packages/pieces/community/webling/src/index.ts",
|
||||
"assets": [
|
||||
"packages/pieces/community/webling/*.md",
|
||||
{
|
||||
"input": "packages/pieces/community/webling/src/i18n",
|
||||
"output": "./src/i18n",
|
||||
"glob": "**/!(i18n.json)"
|
||||
}
|
||||
],
|
||||
"buildableProjectDepsInPackageJsonType": "dependencies",
|
||||
"updateBuildableProjectDepsInPackageJson": true
|
||||
},
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
"prebuild"
|
||||
]
|
||||
},
|
||||
"nx-release-publish": {
|
||||
"options": {
|
||||
"packageRoot": "dist/{projectRoot}"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": [
|
||||
"{options.outputFile}"
|
||||
]
|
||||
},
|
||||
"prebuild": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"cwd": "packages/pieces/community/webling",
|
||||
"command": "bun install --no-save --silent"
|
||||
},
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Base URL": "Basis-URL",
|
||||
"API Key": "API-Schlüssel",
|
||||
"Get Events by ID": "Events per ID abrufen",
|
||||
"Gets event data by a list of event IDs and optional calendar ID to filter.": "Ruft Ereignisdaten durch eine Liste von Ereignis-IDs und optionale Kalender-ID zum Filtern ab.",
|
||||
"Event ID list": "Ereignis-ID-Liste",
|
||||
"Calendar": "Kalender",
|
||||
"Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.": "Durch Komma getrennte Liste von Ereignis-IDs (z.B. '536,525,506,535'). Wenn mindestens eine ID nicht existiert, gibt die ganze Abfrage einen 404-Fehler zurück.",
|
||||
"Calendar to filter the events by.": "Kalender zum Filtern der Ereignisse.",
|
||||
"New or Updated Event": "Neues oder aktualisiertes Ereignis",
|
||||
"On Changed Data": "Bei geänderten Daten",
|
||||
"Triggers when an event is added or updated.": "Wird ausgelöst, wenn ein Ereignis hinzugefügt oder aktualisiert wird.",
|
||||
"Triggers when anything was added, updated or deleted since last request.": "Wird ausgelöst, wenn seit der letzten Anfrage etwas hinzugefügt, aktualisiert oder gelöscht wurde."
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Base URL": "URL base",
|
||||
"API Key": "Clave API",
|
||||
"Get Events by ID": "Obtener eventos por ID",
|
||||
"Gets event data by a list of event IDs and optional calendar ID to filter.": "Obtiene los datos del evento por una lista de IDs de eventos y el ID de calendario opcional para filtrar.",
|
||||
"Event ID list": "Lista de eventos ID",
|
||||
"Calendar": "Calendario",
|
||||
"Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.": "Lista separada por comas de IDs de eventos (por ejemplo, '536,525,506,535'). Cuando al menos un ID no existe la consulta completa devuelve un error 404.",
|
||||
"Calendar to filter the events by.": "Calendario para filtrar los eventos.",
|
||||
"New or Updated Event": "Evento nuevo o actualizado",
|
||||
"On Changed Data": "Al cambiar los datos",
|
||||
"Triggers when an event is added or updated.": "Dispara cuando se agrega o actualiza un evento.",
|
||||
"Triggers when anything was added, updated or deleted since last request.": "Dispara cuando algo fue añadido, actualizado o eliminado desde la última petición."
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Base URL": "URL de base",
|
||||
"API Key": "Clé API",
|
||||
"Get Events by ID": "Obtenir des événements par ID",
|
||||
"Gets event data by a list of event IDs and optional calendar ID to filter.": "Récupère les données d'événement par une liste d'ID d'événements et l'ID de calendrier facultatif à filtrer.",
|
||||
"Event ID list": "Liste des ID d'événements",
|
||||
"Calendar": "Calendrier",
|
||||
"Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.": "Liste des ID d'événements séparés par des virgules (par exemple '536,525,506,535'). Quand au moins un ID n'existe pas, la requête entière renvoie une erreur 404.",
|
||||
"Calendar to filter the events by.": "Calendrier pour filtrer les événements.",
|
||||
"New or Updated Event": "Nouvel événement ou mise à jour",
|
||||
"On Changed Data": "Sur les données modifiées",
|
||||
"Triggers when an event is added or updated.": "Se déclenche lorsqu'un événement est ajouté ou mis à jour.",
|
||||
"Triggers when anything was added, updated or deleted since last request.": "Déclenche quand quelque chose a été ajouté, mis à jour ou supprimé depuis la dernière requête."
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Base URL": "ベースURL",
|
||||
"API Key": "API キー",
|
||||
"Get Events by ID": "イベントを ID で取得する",
|
||||
"Gets event data by a list of event IDs and optional calendar ID to filter.": "イベント ID と任意のカレンダー ID のリストからフィルターを取得します。",
|
||||
"Event ID list": "イベントIDリスト",
|
||||
"Calendar": "カレンダー",
|
||||
"Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.": "イベントIDのカンマ区切りのリスト(例:'536,525,506,535')。少なくとも1つのIDが存在しない場合、クエリ全体が404エラーを返します。",
|
||||
"Calendar to filter the events by.": "イベントをフィルタリングするカレンダーです。",
|
||||
"New or Updated Event": "新規または更新されたイベント",
|
||||
"On Changed Data": "変更されたデータ",
|
||||
"Triggers when an event is added or updated.": "イベントが追加または更新されたときにトリガーします.",
|
||||
"Triggers when anything was added, updated or deleted since last request.": "前回のリクエストから何かが追加されたとき、更新または削除されたときにトリガーします。"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Base URL": "Basis URL",
|
||||
"API Key": "API Sleutel",
|
||||
"Get Events by ID": "Events ophalen via ID",
|
||||
"Gets event data by a list of event IDs and optional calendar ID to filter.": "Haalt gegevens van afspraken op met een lijst van event IDs en optionele kalender ID om te filteren.",
|
||||
"Event ID list": "Event ID lijst",
|
||||
"Calendar": "Kalender",
|
||||
"Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.": "Kommagescheiden lijst met event IDs (bijv. '536,525,506,535'). Wanneer ten minste één ID niet bestaat geeft de hele query een 404 fout.",
|
||||
"Calendar to filter the events by.": "Kalender om gebeurtenissen op te filteren.",
|
||||
"New or Updated Event": "Nieuwe of Bijgewerkte gebeurtenis",
|
||||
"On Changed Data": "Bij Gewijzigde gegevens",
|
||||
"Triggers when an event is added or updated.": "Triggert wanneer een gebeurtenis wordt toegevoegd of bijgewerkt.",
|
||||
"Triggers when anything was added, updated or deleted since last request.": "Triggers wanneer er iets is toegevoegd, bijgewerkt of verwijderd sinds de laatste aanvraag."
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Base URL": "URL Base",
|
||||
"API Key": "Chave de API",
|
||||
"Get Events by ID": "Obter eventos por ID",
|
||||
"Gets event data by a list of event IDs and optional calendar ID to filter.": "Obtém dados de evento por uma lista de IDs de evento e ID de calendário opcional para filtrar.",
|
||||
"Event ID list": "Lista de ID",
|
||||
"Calendar": "calendário",
|
||||
"Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.": "Lista separada por vírgulas de IDs de eventos (por exemplo, '536,525,506,535'). Quando pelo menos um ID não existe, toda a consulta retorna um erro 404.",
|
||||
"Calendar to filter the events by.": "Calendário para filtrar os eventos.",
|
||||
"New or Updated Event": "Evento novo ou atualizado",
|
||||
"On Changed Data": "Em Dados Alterados",
|
||||
"Triggers when an event is added or updated.": "Dispara quando um evento é adicionado ou atualizado.",
|
||||
"Triggers when anything was added, updated or deleted since last request.": "Dispara quando qualquer coisa foi adicionada, atualizada ou excluída desde a última solicitação."
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"Webling": "Ветер",
|
||||
"Base URL": "Базовый URL",
|
||||
"API Key": "Ключ API",
|
||||
"Get Events by ID": "Получить события по ID",
|
||||
"Gets event data by a list of event IDs and optional calendar ID to filter.": "Получает данные событий списком идентификаторов событий и необязательным идентификатором календаря для фильтрации.",
|
||||
"Event ID list": "Список событий",
|
||||
"Calendar": "Календарь",
|
||||
"Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.": "Разделенный запятыми список идентификаторов событий (например, '536,525,506,535'). Если хотя бы один ID не существует весь запрос возвращает ошибку 404.",
|
||||
"Calendar to filter the events by.": "Календарь для фильтрации событий.",
|
||||
"New or Updated Event": "Новое или обновленное событие",
|
||||
"On Changed Data": "При изменении данных",
|
||||
"Triggers when an event is added or updated.": "Триггеры при добавлении или обновлении события.",
|
||||
"Triggers when anything was added, updated or deleted since last request.": "Включает при добавлении, обновлении или удалении с момента последнего запроса."
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Base URL": "Base URL",
|
||||
"API Key": "API Key",
|
||||
"Get Events by ID": "Get Events by ID",
|
||||
"Gets event data by a list of event IDs and optional calendar ID to filter.": "Gets event data by a list of event IDs and optional calendar ID to filter.",
|
||||
"Event ID list": "Event ID list",
|
||||
"Calendar": "Calendar",
|
||||
"Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.": "Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.",
|
||||
"Calendar to filter the events by.": "Calendar to filter the events by.",
|
||||
"New or Updated Event": "New or Updated Event",
|
||||
"On Changed Data": "On Changed Data",
|
||||
"Triggers when an event is added or updated.": "Triggers when an event is added or updated.",
|
||||
"Triggers when anything was added, updated or deleted since last request.": "Triggers when anything was added, updated or deleted since last request."
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"Webling": "Webling",
|
||||
"Base URL": "Base URL",
|
||||
"API Key": "API Key",
|
||||
"Get Events by ID": "Get Events by ID",
|
||||
"Gets event data by a list of event IDs and optional calendar ID to filter.": "Gets event data by a list of event IDs and optional calendar ID to filter.",
|
||||
"Event ID list": "Event ID list",
|
||||
"Calendar": "Calendar",
|
||||
"Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.": "Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.",
|
||||
"Calendar to filter the events by.": "Calendar to filter the events by.",
|
||||
"New or Updated Event": "New or Updated Event",
|
||||
"On Changed Data": "On Changed Data",
|
||||
"Triggers when an event is added or updated.": "Triggers when an event is added or updated.",
|
||||
"Triggers when anything was added, updated or deleted since last request.": "Triggers when anything was added, updated or deleted since last request."
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Base URL": "基本网址",
|
||||
"API Key": "API 密钥",
|
||||
"Get Events by ID": "Get Events by ID",
|
||||
"Gets event data by a list of event IDs and optional calendar ID to filter.": "Gets event data by a list of event IDs and optional calendar ID to filter.",
|
||||
"Event ID list": "Event ID list",
|
||||
"Calendar": "Calendar",
|
||||
"Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.": "Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.",
|
||||
"Calendar to filter the events by.": "Calendar to filter the events by.",
|
||||
"New or Updated Event": "New or Updated Event",
|
||||
"On Changed Data": "On Changed Data",
|
||||
"Triggers when an event is added or updated.": "Triggers when an event is added or updated.",
|
||||
"Triggers when anything was added, updated or deleted since last request.": "Triggers when anything was added, updated or deleted since last request."
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import {
|
||||
httpClient,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
} from '@activepieces/pieces-common';
|
||||
import {
|
||||
createPiece,
|
||||
PieceAuth,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { onEventChanged } from './lib/triggers/calendar-event';
|
||||
import { onChangedData } from './lib/triggers/on-changed-data';
|
||||
import { PieceCategory } from '@activepieces/shared';
|
||||
import { eventsById } from './lib/actions/get-events-by-id';
|
||||
|
||||
export const weblingAuth = PieceAuth.CustomAuth({
|
||||
required: true,
|
||||
props: {
|
||||
baseUrl: Property.ShortText({
|
||||
displayName: 'Base URL',
|
||||
required: true,
|
||||
defaultValue: 'example.webling.ch',
|
||||
}),
|
||||
apikey: PieceAuth.SecretText({
|
||||
displayName: 'API Key',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
validate: async ({ auth }) => {
|
||||
try {
|
||||
const request: HttpRequest = {
|
||||
method: HttpMethod.GET,
|
||||
url: `https://${auth.baseUrl}/api/1/member`,
|
||||
headers: {
|
||||
apikey: auth.apikey,
|
||||
},
|
||||
};
|
||||
await httpClient.sendRequest(request);
|
||||
return {
|
||||
valid: true,
|
||||
};
|
||||
} catch (e: any) {
|
||||
return {
|
||||
valid: false,
|
||||
error: e?.message,
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const webling = createPiece({
|
||||
displayName: 'Webling',
|
||||
auth: weblingAuth,
|
||||
minimumSupportedRelease: '0.30.0',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/webling.png',
|
||||
categories: [PieceCategory.PRODUCTIVITY],
|
||||
authors: ['felifluid'],
|
||||
actions: [eventsById],
|
||||
triggers: [onEventChanged, onChangedData],
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
import { weblingAuth } from '../../index';
|
||||
import { createAction, PiecePropValueSchema, Property } from '@activepieces/pieces-framework';
|
||||
import { getCalendars, getEventsById } from '../common/helpers';
|
||||
import { z } from 'zod';
|
||||
import { propsValidation } from '@activepieces/pieces-common';
|
||||
|
||||
export const eventsById = createAction({
|
||||
auth: weblingAuth,
|
||||
name: 'EventsById',
|
||||
displayName: 'Get Events by ID',
|
||||
description:
|
||||
'Gets event data by a list of event IDs and optional calendar ID to filter.',
|
||||
props: {
|
||||
eventIds: Property.ShortText({
|
||||
displayName: 'Event ID list',
|
||||
required: true,
|
||||
description:
|
||||
"Comma separated list of event IDs (e.g. '536,525,506,535'). When at least one ID doesn't exist the whole query return a 404 error.",
|
||||
}),
|
||||
calendarId: Property.Dropdown<string,false,typeof weblingAuth>({
|
||||
auth: weblingAuth,
|
||||
displayName: 'Calendar',
|
||||
description: 'Calendar to filter the events by.',
|
||||
refreshers: [],
|
||||
required: false,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const authProp = auth;
|
||||
const calendars = await getCalendars(authProp);
|
||||
return {
|
||||
disabled: false,
|
||||
options: calendars.map((calendar) => {
|
||||
return {
|
||||
label: calendar.properties.title,
|
||||
value: calendar.id,
|
||||
};
|
||||
}),
|
||||
};
|
||||
},
|
||||
}),
|
||||
},
|
||||
async run(configValue) {
|
||||
const { eventIds: eventIds, calendarId: calendarId } =
|
||||
configValue.propsValue;
|
||||
|
||||
await propsValidation.validateZod(configValue.propsValue, {
|
||||
eventIds: z.string().regex(/^\d+(,\d+)*$/),
|
||||
});
|
||||
|
||||
const events = await getEventsById(configValue.auth, eventIds);
|
||||
if (calendarId) {
|
||||
return events.filter((event) => event.parents.includes(calendarId));
|
||||
}
|
||||
return events;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,111 @@
|
||||
import { weblingAuth } from '../../index';
|
||||
import {
|
||||
httpClient,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { AppConnectionValueForAuthProperty, PiecePropValueSchema } from '@activepieces/pieces-framework';
|
||||
import { CalendarObject, WeblingCalendarEvent, WeblingChanges } from './types';
|
||||
|
||||
export async function callApi<Type>(
|
||||
authProp: AppConnectionValueForAuthProperty<typeof weblingAuth>,
|
||||
request: string,
|
||||
) {
|
||||
const httpRequest: HttpRequest = {
|
||||
method: HttpMethod.GET,
|
||||
url: `https://${authProp.props.baseUrl}/api/1/${request}`,
|
||||
headers: {
|
||||
apikey: authProp.props.apikey,
|
||||
},
|
||||
};
|
||||
const response = await httpClient.sendRequest<Type>(httpRequest);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function getChanges(
|
||||
authProp: AppConnectionValueForAuthProperty<typeof weblingAuth>,
|
||||
|
||||
lastFetchEpochMS: number,
|
||||
): Promise<WeblingChanges> {
|
||||
// Webling API breaks if unix timestamp is too far in the past
|
||||
if (lastFetchEpochMS === 0) {
|
||||
const today = new Date();
|
||||
const minUpdated = new Date();
|
||||
minUpdated.setDate(today.getDate() - 7);
|
||||
lastFetchEpochMS = minUpdated.getTime();
|
||||
}
|
||||
|
||||
const response = await callApi<WeblingChanges>(
|
||||
authProp,
|
||||
`/changes/${lastFetchEpochMS / 1000}` // webling uses seconds instead of milliseconds
|
||||
);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
export async function getCalendars(
|
||||
authProp: AppConnectionValueForAuthProperty<typeof weblingAuth>
|
||||
): Promise<CalendarObject[]> {
|
||||
const response = await callApi<CalendarObject[]>(
|
||||
authProp,
|
||||
'calendar?format=full'
|
||||
);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
export async function getAllEvents(
|
||||
authProp: AppConnectionValueForAuthProperty<typeof weblingAuth>,
|
||||
calendarId: string,
|
||||
): Promise<WeblingCalendarEvent[]> {
|
||||
const response = await callApi<WeblingCalendarEvent[]>(
|
||||
authProp,
|
||||
`calendarevent?filter=$parents.$id=${calendarId}&format=full`
|
||||
);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
export async function getEventsById(
|
||||
authProp: AppConnectionValueForAuthProperty<typeof weblingAuth>,
|
||||
|
||||
eventIds: string,
|
||||
): Promise<WeblingCalendarEvent[]> {
|
||||
|
||||
const request = `calendarevent/${eventIds}`
|
||||
|
||||
const response = await callApi<WeblingCalendarEvent[]>(
|
||||
authProp,
|
||||
request
|
||||
);
|
||||
|
||||
return response.body;
|
||||
};
|
||||
|
||||
export async function getUpdatedOrNewEvents(
|
||||
authProp: AppConnectionValueForAuthProperty<typeof weblingAuth>,
|
||||
calendarId: string,
|
||||
lastFetchEpochMS: number
|
||||
): Promise<WeblingCalendarEvent[]> {
|
||||
// get changes since last call
|
||||
const weblingChanges: WeblingChanges = await getChanges(
|
||||
authProp,
|
||||
lastFetchEpochMS / 1000
|
||||
);
|
||||
|
||||
// this will also include ids of deleted objects
|
||||
const changedEvents: string[] = weblingChanges.objects.calendarevents ?? [];
|
||||
|
||||
const deletedObjects: string[] = weblingChanges.deleted ?? [];
|
||||
|
||||
// filter out already deleted objects to treat seperately
|
||||
// including a deleted event in a query list will result in a 404 response for the whole query
|
||||
const updatedOrNewEvents: string[] = changedEvents.filter(
|
||||
(event) => !deletedObjects.includes(event)
|
||||
);
|
||||
|
||||
const response = await callApi<WeblingCalendarEvent[]>(
|
||||
authProp,
|
||||
`calendarevent/${updatedOrNewEvents.join(
|
||||
','
|
||||
)}?format=full&filter=$parents.$id=${calendarId}`
|
||||
);
|
||||
return response.body;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { PiecePropValueSchema, Property } from '@activepieces/pieces-framework';
|
||||
import { getCalendars } from './helpers';
|
||||
import { weblingAuth } from '../../index';
|
||||
|
||||
export const weblingCommon = {
|
||||
calendarDropdown: () => {
|
||||
return Property.Dropdown<string,true,typeof weblingAuth>({
|
||||
auth: weblingAuth,
|
||||
displayName: 'Calendar',
|
||||
refreshers: [],
|
||||
required: true,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const calendars = await getCalendars(auth);
|
||||
return {
|
||||
disabled: false,
|
||||
options: calendars.map((calendar) => {
|
||||
return {
|
||||
label: calendar.properties.title,
|
||||
value: calendar.id,
|
||||
};
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,111 @@
|
||||
export interface MetaObject {
|
||||
created: string;
|
||||
createuser: {
|
||||
label: string;
|
||||
type: string;
|
||||
};
|
||||
lastmodified: string;
|
||||
lastmodifieduser: {
|
||||
label: string;
|
||||
type: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CalendarObject {
|
||||
type: string;
|
||||
meta: MetaObject;
|
||||
readonly: boolean;
|
||||
properties: {
|
||||
title: string;
|
||||
color: string;
|
||||
isPublic: boolean;
|
||||
publicHash: string;
|
||||
icsHash: string;
|
||||
};
|
||||
parents: [];
|
||||
children: {
|
||||
calendarevent: string[];
|
||||
};
|
||||
links: object;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface CalendarList {
|
||||
objects: CalendarObject[];
|
||||
}
|
||||
|
||||
export interface WeblingCalendarEvent {
|
||||
type: 'calendarevent';
|
||||
meta: MetaObject;
|
||||
readonly: boolean;
|
||||
properties: {
|
||||
title: string;
|
||||
description: string;
|
||||
place: string;
|
||||
begin: string;
|
||||
end: string;
|
||||
duration: string;
|
||||
isAllDay: boolean;
|
||||
isRecurring: boolean;
|
||||
status: string;
|
||||
recurrencePattern: string | null;
|
||||
enableParticipantSignup: boolean;
|
||||
enableParticipantMaybeState: boolean;
|
||||
isSignupBinding: boolean;
|
||||
maxParticipants: string | null;
|
||||
signedupParticipants: string;
|
||||
signupAllowedUntil: string | null;
|
||||
doAutoAcceptParticipants: boolean;
|
||||
questionSchema: string | null;
|
||||
showParticipationsInPortal: boolean;
|
||||
showAllAnswersInPortal: boolean;
|
||||
};
|
||||
parents: string[];
|
||||
children: object;
|
||||
links: object;
|
||||
}
|
||||
|
||||
export interface WeblingChanges {
|
||||
objects: WeblingObjectTypes;
|
||||
deleted: string[];
|
||||
context: object[];
|
||||
definitions: object[];
|
||||
settings: boolean;
|
||||
quota: boolean;
|
||||
subscription: boolean;
|
||||
revision: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
// this list might be incomplete
|
||||
export interface WeblingObjectTypes {
|
||||
account?: string[];
|
||||
accountgroup?: string[];
|
||||
accountgrouptemplate?: string[];
|
||||
accounttemplate?: string[];
|
||||
apikey?: string[];
|
||||
article?: string[];
|
||||
articlegroup?: string[];
|
||||
calendar?: string[];
|
||||
calendarevents?: string[];
|
||||
comment?: string[];
|
||||
debitor?: string[];
|
||||
debitorcategory?: string[];
|
||||
document?: string[];
|
||||
domain?: string[];
|
||||
email?: string[];
|
||||
entry?: string[];
|
||||
entrygroup?: string[];
|
||||
file?: string[];
|
||||
member?: string[];
|
||||
memberform?: string[];
|
||||
membergroup?: string[];
|
||||
page?: string[];
|
||||
participant?: string[];
|
||||
period?: string[];
|
||||
periodchain?: string[];
|
||||
periodgroup?: string[];
|
||||
settings?: string[];
|
||||
template?: string[];
|
||||
user?: string[];
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import {
|
||||
DedupeStrategy,
|
||||
Polling,
|
||||
pollingHelper,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { weblingAuth } from '../../index';
|
||||
import { weblingCommon } from '../common';
|
||||
import { WeblingCalendarEvent } from '../common/types';
|
||||
import { getUpdatedOrNewEvents } from '../common/helpers';
|
||||
|
||||
const polling: Polling<
|
||||
AppConnectionValueForAuthProperty<typeof weblingAuth>,
|
||||
{ calendarId?: string }
|
||||
> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
items: async ({ auth, propsValue: { calendarId }, lastFetchEpochMS }) => {
|
||||
// implement the logic to fetch the items
|
||||
const items: WeblingCalendarEvent[] =
|
||||
(await getUpdatedOrNewEvents(auth, calendarId!, lastFetchEpochMS)) ?? [];
|
||||
return items.map((item) => ({
|
||||
epochMilliSeconds: new Date(item.meta.lastmodified).getTime(),
|
||||
data: item,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
export const onEventChanged = createTrigger({
|
||||
auth: weblingAuth,
|
||||
name: 'onEventChanged',
|
||||
displayName: 'New or Updated Event',
|
||||
description: 'Triggers when an event is added or updated.',
|
||||
props: {
|
||||
calendarId: weblingCommon.calendarDropdown(),
|
||||
},
|
||||
sampleData: {},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async test(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
return await pollingHelper.test(polling, {
|
||||
store,
|
||||
auth,
|
||||
propsValue: {
|
||||
calendarId: propsValue.calendarId,
|
||||
},
|
||||
files: context.files,
|
||||
});
|
||||
},
|
||||
async onEnable(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
await pollingHelper.onEnable(polling, {
|
||||
store,
|
||||
auth,
|
||||
propsValue: {
|
||||
calendarId: propsValue.calendarId,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
await pollingHelper.onDisable(polling, {
|
||||
store,
|
||||
auth,
|
||||
propsValue: {
|
||||
calendarId: propsValue.calendarId,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
return await pollingHelper.poll(polling, {
|
||||
store,
|
||||
auth,
|
||||
propsValue: {
|
||||
calendarId: propsValue.calendarId,
|
||||
},
|
||||
files: context.files,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,119 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import {
|
||||
DedupeStrategy,
|
||||
Polling,
|
||||
pollingHelper,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { weblingAuth } from '../../index';
|
||||
import { WeblingChanges } from '../common/types';
|
||||
import { getChanges } from '../common/helpers';
|
||||
|
||||
const polling: Polling<
|
||||
AppConnectionValueForAuthProperty<typeof weblingAuth>,
|
||||
{ calendarId?: string }
|
||||
> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
|
||||
const changes: WeblingChanges = await getChanges(auth, lastFetchEpochMS);
|
||||
const items = [
|
||||
{
|
||||
epochMilliSeconds: Date.now(), // maybe use revision instead?
|
||||
data: changes,
|
||||
},
|
||||
];
|
||||
return items;
|
||||
},
|
||||
};
|
||||
|
||||
export const onChangedData = createTrigger({
|
||||
auth: weblingAuth,
|
||||
name: 'onChangedData',
|
||||
displayName: 'On Changed Data',
|
||||
description:
|
||||
'Triggers when anything was added, updated or deleted since last request.',
|
||||
props: {},
|
||||
sampleData: {
|
||||
objects: {
|
||||
account: [244, 246],
|
||||
accountgroup: [242],
|
||||
accountgrouptemplate: [241],
|
||||
accounttemplate: [243, 245, 247, 248, 250],
|
||||
apikey: [5241],
|
||||
article: [4579, 4580],
|
||||
articlegroup: [4578],
|
||||
calendar: [235, 4428],
|
||||
calendarevent: [4431, 4434, 4435, 4436],
|
||||
comment: [4423],
|
||||
debitor: [1205, 1208],
|
||||
debitorcategory: [650],
|
||||
document: [4506],
|
||||
documentgroup: [114],
|
||||
domain: [1771],
|
||||
email: [5085],
|
||||
entry: [321, 323, 338],
|
||||
entrygroup: [320, 322, 337],
|
||||
file: [4525],
|
||||
member: [4270, 4271, 398, 399],
|
||||
memberform: [4491],
|
||||
membergroup: [100],
|
||||
page: [4495],
|
||||
participant: [4460],
|
||||
period: [240],
|
||||
periodchain: [239],
|
||||
periodgroup: [238],
|
||||
settings: [233],
|
||||
template: [228],
|
||||
user: [120, 343, 345],
|
||||
},
|
||||
deleted: [235],
|
||||
context: [],
|
||||
definitions: ['member'],
|
||||
settings: false,
|
||||
quota: true,
|
||||
subscription: true,
|
||||
revision: 4758,
|
||||
version: 2560,
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async test(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
return await pollingHelper.test(polling, {
|
||||
store,
|
||||
auth,
|
||||
propsValue,
|
||||
files: context.files,
|
||||
});
|
||||
},
|
||||
async onEnable(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
await pollingHelper.onEnable(polling, {
|
||||
store,
|
||||
auth,
|
||||
propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
await pollingHelper.onDisable(polling, {
|
||||
store,
|
||||
auth,
|
||||
propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
return await pollingHelper.poll(polling, {
|
||||
store,
|
||||
auth,
|
||||
propsValue,
|
||||
files: context.files,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noPropertyAccessFromIndexSignature": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"outDir": "../../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user