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,27 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { getBlogPost } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
|
||||
export const getBlogPostAction = createAction({
|
||||
name: 'get_blog_post',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Get Blog Post',
|
||||
description: 'Get a blog post from Total CMS',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the content to retrieve',
|
||||
required: true,
|
||||
}),
|
||||
permalink: Property.ShortText({
|
||||
displayName: 'Permalink',
|
||||
description: 'The permalink of the post to retrieve',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const slug = context.propsValue.slug;
|
||||
const permalink = context.propsValue.permalink;
|
||||
return await getBlogPost(context.auth, slug, permalink);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { getContent } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
|
||||
export const getContentAction = createAction({
|
||||
name: 'get_content',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Get Content',
|
||||
description: 'Get content from your Total CMS website',
|
||||
props: {
|
||||
type: Property.StaticDropdown({
|
||||
displayName: 'Data Type',
|
||||
description: 'The type of data to return',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Blog', value: 'blog' },
|
||||
{ label: 'Datastore', value: 'datastore' },
|
||||
{ label: 'Date', value: 'date' },
|
||||
{ label: 'Depot', value: 'depot' },
|
||||
{ label: 'Feed', value: 'feed' },
|
||||
{ label: 'File', value: 'file' },
|
||||
{ label: 'Gallery', value: 'gallery' },
|
||||
{ label: 'Image', value: 'image' },
|
||||
{ label: 'Ratings', value: 'ratings' },
|
||||
{ label: 'Text', value: 'text' },
|
||||
{ label: 'Toggle', value: 'toggle' },
|
||||
{ label: 'Video', value: 'video' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the content to retrieve',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const type = context.propsValue.type;
|
||||
const slug = context.propsValue.slug;
|
||||
return await getContent(context.auth, type, slug);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,127 @@
|
||||
import {
|
||||
createAction,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { saveBlogGallery } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
import { z } from 'zod';
|
||||
import { propsValidation } from '@activepieces/pieces-common';
|
||||
|
||||
export const saveBlogGalleryAction = createAction({
|
||||
name: 'save_blog_gallery',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Save Blog Post Gallery Image',
|
||||
description: 'Save image to Total CMS blog post gallery',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the blog to save',
|
||||
required: true,
|
||||
}),
|
||||
permalink: Property.ShortText({
|
||||
displayName: 'Permalink',
|
||||
description: 'The permalink of the blog post to save',
|
||||
required: true,
|
||||
}),
|
||||
image: Property.File({
|
||||
displayName: 'Image',
|
||||
description: 'The image to save',
|
||||
required: true,
|
||||
}),
|
||||
alt: Property.ShortText({
|
||||
displayName: 'Alt Text',
|
||||
description: 'The alt text for the image',
|
||||
required: true,
|
||||
}),
|
||||
quality: Property.Number({
|
||||
displayName: 'Thumbnail Quality',
|
||||
description: 'The quality of the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 85,
|
||||
}),
|
||||
scaleTh: Property.Number({
|
||||
displayName: 'Thumbnail Scale',
|
||||
description: 'The scale of the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 400,
|
||||
}),
|
||||
scaleSq: Property.Number({
|
||||
displayName: 'Thumbnail Square Scale',
|
||||
description: 'The scale of the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 400,
|
||||
}),
|
||||
resize: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Resize Method',
|
||||
description: 'The method to use when resizing the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'auto',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Auto', value: 'auto' },
|
||||
{ label: 'Landscape', value: 'landscape' },
|
||||
{ label: 'Portrait', value: 'portrait' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
lcrop: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Landscape Crop',
|
||||
description:
|
||||
'The method to use when cropping the landscape thumbnail for the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'center',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Left', value: 'left' },
|
||||
{ label: 'Center', value: 'center' },
|
||||
{ label: 'Right', value: 'right' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
pcrop: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Landscape Crop',
|
||||
description:
|
||||
'The method to use when cropping the landscape thumbnail for the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'middle',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Top', value: 'top' },
|
||||
{ label: 'Middle', value: 'middle' },
|
||||
{ label: 'Bottom', value: 'bottom' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
altMeta: Property.Checkbox({
|
||||
displayName: 'Pull Alt Text from Meta Data',
|
||||
description:
|
||||
'Pull the alt text from the meta data of the image. If set, place placeholder text in the alt text field above.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
await propsValidation.validateZod(context.propsValue, {
|
||||
quality: z.number().min(1).max(100),
|
||||
scaleTh: z.number().min(1),
|
||||
scaleSq: z.number().min(1),
|
||||
});
|
||||
const slug = context.propsValue.slug;
|
||||
const image = {
|
||||
filename: context.propsValue.image.filename,
|
||||
base64: context.propsValue.image.base64,
|
||||
};
|
||||
return await saveBlogGallery(context.auth, slug, image, {
|
||||
permalink: context.propsValue.permalink,
|
||||
thumbs: 1,
|
||||
optimize: 1,
|
||||
alttype: context.propsValue.altMeta ? 'meta' : 'user',
|
||||
alt: context.propsValue.alt,
|
||||
quality: context.propsValue.quality,
|
||||
scale_th: context.propsValue.scaleTh,
|
||||
scale_sq: context.propsValue.scaleSq,
|
||||
resize: context.propsValue.resize,
|
||||
lcrop: context.propsValue.lcrop,
|
||||
pcrop: context.propsValue.pcrop,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,131 @@
|
||||
import {
|
||||
createAction,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { z } from 'zod';
|
||||
import { propsValidation } from '@activepieces/pieces-common';
|
||||
import { saveBlogImage } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
|
||||
export const saveBlogImageAction = createAction({
|
||||
name: 'save_blog_image',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Save Blog Post Image',
|
||||
description: 'Save image to Total CMS blog post',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the content to save',
|
||||
required: true,
|
||||
}),
|
||||
permalink: Property.ShortText({
|
||||
displayName: 'Permalink',
|
||||
description: 'The permalink of the blog post to save',
|
||||
required: true,
|
||||
}),
|
||||
image: Property.File({
|
||||
displayName: 'Image',
|
||||
description: 'The image to save',
|
||||
required: true,
|
||||
}),
|
||||
alt: Property.ShortText({
|
||||
displayName: 'Alt Text',
|
||||
description: 'The alt text for the image',
|
||||
required: true,
|
||||
}),
|
||||
quality: Property.Number({
|
||||
displayName: 'Thumbnail Quality',
|
||||
description: 'The quality of the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 85,
|
||||
}),
|
||||
scaleTh: Property.Number({
|
||||
displayName: 'Thumbnail Scale',
|
||||
description: 'The scale of the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 400,
|
||||
}),
|
||||
scaleSq: Property.Number({
|
||||
displayName: 'Thumbnail Square Scale',
|
||||
description: 'The scale of the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 400,
|
||||
}),
|
||||
resize: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Resize Method',
|
||||
description: 'The method to use when resizing the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'auto',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Auto', value: 'auto' },
|
||||
{ label: 'Landscape', value: 'landscape' },
|
||||
{ label: 'Portrait', value: 'portrait' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
lcrop: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Landscape Crop',
|
||||
description:
|
||||
'The method to use when cropping the landscape thumbnail for the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'center',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Left', value: 'left' },
|
||||
{ label: 'Center', value: 'center' },
|
||||
{ label: 'Right', value: 'right' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
pcrop: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Landscape Crop',
|
||||
description:
|
||||
'The method to use when cropping the landscape thumbnail for the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'middle',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Top', value: 'top' },
|
||||
{ label: 'Middle', value: 'middle' },
|
||||
{ label: 'Bottom', value: 'bottom' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
altMeta: Property.Checkbox({
|
||||
displayName: 'Pull Alt Text from Meta Data',
|
||||
description:
|
||||
'Pull the alt text from the meta data of the image. If set, place placeholder text in the alt text field above.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
await propsValidation.validateZod(context.propsValue, {
|
||||
quality: z.number().min(1).max(100),
|
||||
scaleTh: z.number().min(1),
|
||||
scaleSq: z.number().min(1),
|
||||
});
|
||||
|
||||
const slug = context.propsValue.slug;
|
||||
const image = {
|
||||
filename: context.propsValue.image.filename,
|
||||
base64: context.propsValue.image.base64,
|
||||
};
|
||||
return await saveBlogImage(context.auth, slug, image, {
|
||||
permalink: context.propsValue.permalink,
|
||||
thumbs: 1,
|
||||
optimize: 1,
|
||||
alttype: context.propsValue.altMeta ? 'meta' : 'user',
|
||||
alt: context.propsValue.alt,
|
||||
quality: context.propsValue.quality,
|
||||
scale_th: context.propsValue.scaleTh,
|
||||
scale_sq: context.propsValue.scaleSq,
|
||||
resize: context.propsValue.resize,
|
||||
lcrop: context.propsValue.lcrop,
|
||||
pcrop: context.propsValue.pcrop,
|
||||
// Cannot add support for ext option with how this API is built.
|
||||
// it would break the saving of the blog post since it would try
|
||||
// to save the blog post JSON file with the extension of the ext option
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,132 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { saveContent } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
|
||||
export const saveBlogPostAction = createAction({
|
||||
name: 'save_blog_post',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Save Blog Post',
|
||||
description: 'Save blog content to Total CMS',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the content to save',
|
||||
required: true,
|
||||
}),
|
||||
permalink: Property.ShortText({
|
||||
displayName: 'Permalink',
|
||||
description:
|
||||
'The permalink of the blog post. Ensure this is unique or it will overwrite the existing post.',
|
||||
required: true,
|
||||
}),
|
||||
title: Property.ShortText({
|
||||
displayName: 'Title',
|
||||
description: 'The title of the blog post',
|
||||
required: false,
|
||||
}),
|
||||
timestamp: Property.Number({
|
||||
displayName: 'Date (Unix Timestamp)',
|
||||
description: 'The date in unix timestamp format',
|
||||
required: false,
|
||||
}),
|
||||
summary: Property.LongText({
|
||||
displayName: 'Summary',
|
||||
description: 'The summary of the blog post',
|
||||
required: false,
|
||||
}),
|
||||
content: Property.LongText({
|
||||
displayName: 'Content',
|
||||
description: 'The content of the blog post',
|
||||
required: false,
|
||||
}),
|
||||
extra: Property.LongText({
|
||||
displayName: 'Extra Content',
|
||||
description: 'The extra content of the blog post',
|
||||
required: false,
|
||||
}),
|
||||
extra2: Property.LongText({
|
||||
displayName: 'Extra Content 2',
|
||||
description: 'The extra content 2 of the blog post',
|
||||
required: false,
|
||||
}),
|
||||
media: Property.ShortText({
|
||||
displayName: 'Media',
|
||||
description: 'The media of the blog post',
|
||||
required: false,
|
||||
}),
|
||||
rssTitle: Property.ShortText({
|
||||
displayName: 'RSS Title',
|
||||
description: 'The RSS title of the blog post',
|
||||
required: false,
|
||||
}),
|
||||
rssDescription: Property.ShortText({
|
||||
displayName: 'RSS Description',
|
||||
description: 'The RSS description of the blog post',
|
||||
required: false,
|
||||
}),
|
||||
author: Property.ShortText({
|
||||
displayName: 'Author',
|
||||
description: 'The author of the blog post',
|
||||
required: false,
|
||||
}),
|
||||
genre: Property.ShortText({
|
||||
displayName: 'Genre',
|
||||
description: 'The genre of the blog post',
|
||||
required: false,
|
||||
}),
|
||||
categories: Property.ShortText({
|
||||
displayName: 'Categories',
|
||||
description: 'A comma separated list of categories for the blog post',
|
||||
required: false,
|
||||
}),
|
||||
tags: Property.ShortText({
|
||||
displayName: 'Tags',
|
||||
description: 'A comma separated list of tags for the blog post',
|
||||
required: false,
|
||||
}),
|
||||
labels: Property.ShortText({
|
||||
displayName: 'Labels',
|
||||
description: 'A comma separated list of labels for the blog post',
|
||||
required: false,
|
||||
}),
|
||||
draft: Property.Checkbox({
|
||||
displayName: 'Draft',
|
||||
description: 'Set to true to save as a draft',
|
||||
required: false,
|
||||
}),
|
||||
featured: Property.Checkbox({
|
||||
displayName: 'Featured',
|
||||
description: 'Set to true to save as a featured post',
|
||||
required: false,
|
||||
}),
|
||||
archived: Property.Checkbox({
|
||||
displayName: 'Archived',
|
||||
description: 'Set to true to save as an archived post',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const slug = context.propsValue.slug;
|
||||
return await saveContent(context.auth, 'blog', slug, {
|
||||
nodecode: true,
|
||||
permalink: context.propsValue.permalink,
|
||||
title: context.propsValue.title,
|
||||
timestamp: context.propsValue.timestamp?.toString(),
|
||||
summary: context.propsValue.summary,
|
||||
content: context.propsValue.content,
|
||||
extra: context.propsValue.extra,
|
||||
extra2: context.propsValue.extra2,
|
||||
media: context.propsValue.media,
|
||||
rss_title: context.propsValue.rssTitle,
|
||||
rss_description: context.propsValue.rssDescription,
|
||||
author: context.propsValue.author,
|
||||
genre: context.propsValue.genre,
|
||||
categories: context.propsValue.categories,
|
||||
tags: context.propsValue.tags,
|
||||
labels: context.propsValue.labels,
|
||||
draft: context.propsValue.draft ? 'true' : 'false',
|
||||
featured: context.propsValue.featured ? 'true' : 'false',
|
||||
archived: context.propsValue.archived ? 'true' : 'false',
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { saveContent } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
|
||||
export const saveDateAction = createAction({
|
||||
name: 'save_date',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Save Date Content',
|
||||
description: 'Save date content to Total CMS',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the content to save',
|
||||
required: true,
|
||||
}),
|
||||
timestamp: Property.Number({
|
||||
displayName: 'Unix Timestamp',
|
||||
description: 'The unix timestamp to save',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const slug = context.propsValue.slug;
|
||||
const timestamp = context.propsValue.timestamp;
|
||||
return await saveContent(context.auth, 'date', slug, {
|
||||
nodecode: true,
|
||||
timestamp: timestamp.toString(),
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { saveDepot } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
|
||||
export const saveDepotAction = createAction({
|
||||
name: 'save_depot',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Save Depot',
|
||||
description: 'Save file to Total CMS depot',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the depot to save',
|
||||
required: true,
|
||||
}),
|
||||
file: Property.File({
|
||||
displayName: 'File',
|
||||
description: 'The file to save',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const slug = context.propsValue.slug;
|
||||
const file = {
|
||||
filename: context.propsValue.file.filename,
|
||||
base64: context.propsValue.file.base64,
|
||||
};
|
||||
return await saveDepot(context.auth, slug, file);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { saveFile } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
|
||||
export const saveFileAction = createAction({
|
||||
name: 'save_file',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Save File',
|
||||
description: 'Save file to Total CMS',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the file to save',
|
||||
required: true,
|
||||
}),
|
||||
ext: Property.ShortText({
|
||||
displayName: 'File Extension',
|
||||
description: 'The file extension of the file',
|
||||
required: true,
|
||||
}),
|
||||
file: Property.File({
|
||||
displayName: 'File',
|
||||
description: 'The file to save',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const slug = context.propsValue.slug;
|
||||
const file = {
|
||||
filename: context.propsValue.file.filename,
|
||||
base64: context.propsValue.file.base64,
|
||||
};
|
||||
return await saveFile(context.auth, slug, file, {
|
||||
ext: context.propsValue.ext,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,122 @@
|
||||
import {
|
||||
createAction,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { saveGallery } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
import { z } from 'zod';
|
||||
import { propsValidation } from '@activepieces/pieces-common';
|
||||
|
||||
export const saveGalleryAction = createAction({
|
||||
name: 'save_gallery',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Save Gallery Image',
|
||||
description: 'Save image to Total CMS gallery',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the gallery to save',
|
||||
required: true,
|
||||
}),
|
||||
image: Property.File({
|
||||
displayName: 'Image',
|
||||
description: 'The image to save',
|
||||
required: true,
|
||||
}),
|
||||
alt: Property.ShortText({
|
||||
displayName: 'Alt Text',
|
||||
description: 'The alt text for the image',
|
||||
required: true,
|
||||
}),
|
||||
quality: Property.Number({
|
||||
displayName: 'Thumbnail Quality',
|
||||
description: 'The quality of the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 85,
|
||||
}),
|
||||
scaleTh: Property.Number({
|
||||
displayName: 'Thumbnail Scale',
|
||||
description: 'The scale of the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 400,
|
||||
}),
|
||||
scaleSq: Property.Number({
|
||||
displayName: 'Thumbnail Square Scale',
|
||||
description: 'The scale of the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 400,
|
||||
}),
|
||||
resize: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Resize Method',
|
||||
description: 'The method to use when resizing the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'auto',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Auto', value: 'auto' },
|
||||
{ label: 'Landscape', value: 'landscape' },
|
||||
{ label: 'Portrait', value: 'portrait' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
lcrop: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Landscape Crop',
|
||||
description:
|
||||
'The method to use when cropping the landscape thumbnail for the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'center',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Left', value: 'left' },
|
||||
{ label: 'Center', value: 'center' },
|
||||
{ label: 'Right', value: 'right' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
pcrop: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Landscape Crop',
|
||||
description:
|
||||
'The method to use when cropping the landscape thumbnail for the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'middle',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Top', value: 'top' },
|
||||
{ label: 'Middle', value: 'middle' },
|
||||
{ label: 'Bottom', value: 'bottom' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
altMeta: Property.Checkbox({
|
||||
displayName: 'Pull Alt Text from Meta Data',
|
||||
description:
|
||||
'Pull the alt text from the meta data of the image. If set, place placeholder text in the alt text field above.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
await propsValidation.validateZod(context.propsValue, {
|
||||
quality: z.number().min(1).max(100),
|
||||
scaleTh: z.number().min(1),
|
||||
scaleSq: z.number().min(1),
|
||||
});
|
||||
|
||||
const slug = context.propsValue.slug;
|
||||
const image = {
|
||||
filename: context.propsValue.image.filename,
|
||||
base64: context.propsValue.image.base64,
|
||||
};
|
||||
return await saveGallery(context.auth, slug, image, {
|
||||
thumbs: 1,
|
||||
optimize: 1,
|
||||
alttype: context.propsValue.altMeta ? 'meta' : 'user',
|
||||
alt: context.propsValue.alt,
|
||||
quality: context.propsValue.quality,
|
||||
scale_th: context.propsValue.scaleTh,
|
||||
scale_sq: context.propsValue.scaleSq,
|
||||
resize: context.propsValue.resize,
|
||||
lcrop: context.propsValue.lcrop,
|
||||
pcrop: context.propsValue.pcrop,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,134 @@
|
||||
import {
|
||||
createAction,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { saveImage } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
import { z } from 'zod';
|
||||
import { propsValidation } from '@activepieces/pieces-common';
|
||||
|
||||
export const saveImageAction = createAction({
|
||||
name: 'save_image',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Save Image',
|
||||
description: 'Save image to Total CMS',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the content to save',
|
||||
required: true,
|
||||
}),
|
||||
image: Property.File({
|
||||
displayName: 'Image',
|
||||
description: 'The image to save',
|
||||
required: true,
|
||||
}),
|
||||
alt: Property.ShortText({
|
||||
displayName: 'Alt Text',
|
||||
description: 'The alt text for the image',
|
||||
required: true,
|
||||
}),
|
||||
ext: Property.StaticDropdown({
|
||||
displayName: 'Extension',
|
||||
description: 'The extension of the image',
|
||||
required: true,
|
||||
defaultValue: 'jpg',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'jpg', value: 'jpg' },
|
||||
{ label: 'png', value: 'png' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
quality: Property.Number({
|
||||
displayName: 'Thumbnail Quality',
|
||||
description: 'The quality of the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 85,
|
||||
}),
|
||||
scaleTh: Property.Number({
|
||||
displayName: 'Thumbnail Scale',
|
||||
description: 'The scale of the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 400,
|
||||
}),
|
||||
scaleSq: Property.Number({
|
||||
displayName: 'Thumbnail Square Scale',
|
||||
description: 'The scale of the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 400,
|
||||
}),
|
||||
resize: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Resize Method',
|
||||
description: 'The method to use when resizing the thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'auto',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Auto', value: 'auto' },
|
||||
{ label: 'Landscape', value: 'landscape' },
|
||||
{ label: 'Portrait', value: 'portrait' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
lcrop: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Landscape Crop',
|
||||
description:
|
||||
'The method to use when cropping the landscape thumbnail for the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'center',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Left', value: 'left' },
|
||||
{ label: 'Center', value: 'center' },
|
||||
{ label: 'Right', value: 'right' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
pcrop: Property.StaticDropdown({
|
||||
displayName: 'Thumbnail Landscape Crop',
|
||||
description:
|
||||
'The method to use when cropping the landscape thumbnail for the square thumbnail',
|
||||
required: true,
|
||||
defaultValue: 'middle',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Top', value: 'top' },
|
||||
{ label: 'Middle', value: 'middle' },
|
||||
{ label: 'Bottom', value: 'bottom' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
altMeta: Property.Checkbox({
|
||||
displayName: 'Pull Alt Text from Meta Data',
|
||||
description:
|
||||
'Pull the alt text from the meta data of the image. If set, place placeholder text in the alt text field above.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
await propsValidation.validateZod(context.propsValue, {
|
||||
quality: z.number().min(1).max(100),
|
||||
scaleTh: z.number().min(1),
|
||||
scaleSq: z.number().min(1),
|
||||
});
|
||||
const slug = context.propsValue.slug;
|
||||
const image = {
|
||||
filename: context.propsValue.image.filename,
|
||||
base64: context.propsValue.image.base64,
|
||||
};
|
||||
return await saveImage(context.auth, slug, image, {
|
||||
thumbs: 1,
|
||||
optimize: 1,
|
||||
alttype: context.propsValue.altMeta ? 'meta' : 'user',
|
||||
alt: context.propsValue.alt,
|
||||
ext: context.propsValue.ext,
|
||||
quality: context.propsValue.quality,
|
||||
scale_th: context.propsValue.scaleTh,
|
||||
scale_sq: context.propsValue.scaleSq,
|
||||
resize: context.propsValue.resize,
|
||||
lcrop: context.propsValue.lcrop,
|
||||
pcrop: context.propsValue.pcrop,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { saveContent } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
|
||||
export const saveTextAction = createAction({
|
||||
name: 'save_text',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Save Text Content',
|
||||
description: 'Save text content to Total CMS',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the content to save',
|
||||
required: true,
|
||||
}),
|
||||
text: Property.LongText({
|
||||
displayName: 'Text Content',
|
||||
description: 'The text content to save',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const slug = context.propsValue.slug;
|
||||
const text = context.propsValue.text;
|
||||
return await saveContent(context.auth, 'text', slug, {
|
||||
nodecode: true,
|
||||
text: text,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { saveContent } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
|
||||
export const saveToggleAction = createAction({
|
||||
name: 'save_toggle',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Save Toggle',
|
||||
description: 'Save toggle content to Total CMS',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the content to save',
|
||||
required: true,
|
||||
}),
|
||||
status: Property.Checkbox({
|
||||
displayName: 'Status',
|
||||
description: 'The status of the toggle. "true" is on, "false" is off.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const slug = context.propsValue.slug;
|
||||
const status = context.propsValue.status ? 'true' : 'false';
|
||||
return await saveContent(context.auth, 'toggle', slug, {
|
||||
nodecode: true,
|
||||
state: status,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
createAction,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { saveContent } from '../api';
|
||||
import { cmsAuth } from '../auth';
|
||||
import { z } from 'zod';
|
||||
import { propsValidation } from '@activepieces/pieces-common';
|
||||
|
||||
export const saveVideoAction = createAction({
|
||||
name: 'save_video',
|
||||
auth: cmsAuth,
|
||||
displayName: 'Save Video Content',
|
||||
description: 'Save video content to Total CMS',
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the content to save',
|
||||
required: true,
|
||||
}),
|
||||
video: Property.ShortText({
|
||||
displayName: 'Video URL',
|
||||
description: 'The URL of the video to save',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
await propsValidation.validateZod(context.propsValue, {
|
||||
video: z.string().url(),
|
||||
});
|
||||
|
||||
const slug = context.propsValue.slug;
|
||||
const video = context.propsValue.video;
|
||||
return await saveContent(context.auth, 'video', slug, {
|
||||
nodecode: true,
|
||||
video: video,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,173 @@
|
||||
import {
|
||||
httpClient,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
QueryParams,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { TotalCMSAuthType } from './auth';
|
||||
import FormData from 'form-data';
|
||||
|
||||
export type KeyValuePair = {
|
||||
[key: string]: string | boolean | number | object | undefined;
|
||||
};
|
||||
export type FileUpload = { filename: string; base64: string };
|
||||
|
||||
const totalcmsAPI = async (
|
||||
auth: TotalCMSAuthType,
|
||||
type: string,
|
||||
slug: string,
|
||||
query: QueryParams = {},
|
||||
data: KeyValuePair = {},
|
||||
method: HttpMethod = HttpMethod.GET
|
||||
) => {
|
||||
if (method === HttpMethod.GET) {
|
||||
query['slug'] = slug;
|
||||
query['type'] = type;
|
||||
} else {
|
||||
data['slug'] = slug;
|
||||
data['type'] = type;
|
||||
}
|
||||
|
||||
const request: HttpRequest = {
|
||||
body: data,
|
||||
queryParams: query,
|
||||
method: method,
|
||||
url: `${auth.props.domain}/rw_common/plugins/stacks/total-cms/totalapi.php`,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'total-key': auth.props.license,
|
||||
},
|
||||
};
|
||||
const response = await httpClient.sendRequest(request);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`Total CMS API error: ${response.status} ${response.body}`);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: response.body['data'],
|
||||
};
|
||||
};
|
||||
|
||||
const totalcmsUploadAPI = async (
|
||||
auth: TotalCMSAuthType,
|
||||
type: string,
|
||||
slug: string,
|
||||
file: FileUpload,
|
||||
data: KeyValuePair = {},
|
||||
fileName = 'file'
|
||||
) => {
|
||||
const formData = new FormData();
|
||||
formData.append('type', type);
|
||||
formData.append('slug', slug);
|
||||
|
||||
formData.append(fileName, Buffer.from(file.base64, 'base64'), file.filename);
|
||||
|
||||
for (const key in data) {
|
||||
if (fileName !== 'file') {
|
||||
// blog post images use the format image[alt] or gallery[alt]
|
||||
formData.append(`${fileName}[${key}]`, data[key]);
|
||||
}
|
||||
formData.append(key, data[key]);
|
||||
}
|
||||
|
||||
const request: HttpRequest = {
|
||||
body: formData,
|
||||
method: HttpMethod.POST,
|
||||
url: `${auth.props.domain}/rw_common/plugins/stacks/total-cms/totalapi.php`,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
'total-key': auth.props.license,
|
||||
},
|
||||
};
|
||||
const response = await httpClient.sendRequest(request);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`Total CMS API error: ${response.status} ${response.body}`);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: response.body['data'],
|
||||
};
|
||||
};
|
||||
|
||||
export async function saveFile(
|
||||
auth: TotalCMSAuthType,
|
||||
slug: string,
|
||||
file: FileUpload,
|
||||
data: KeyValuePair
|
||||
) {
|
||||
return totalcmsUploadAPI(auth, 'file', slug, file, data);
|
||||
}
|
||||
|
||||
export async function saveDepot(
|
||||
auth: TotalCMSAuthType,
|
||||
slug: string,
|
||||
file: FileUpload
|
||||
) {
|
||||
return totalcmsUploadAPI(auth, 'depot', slug, file);
|
||||
}
|
||||
|
||||
export async function saveImage(
|
||||
auth: TotalCMSAuthType,
|
||||
slug: string,
|
||||
file: FileUpload,
|
||||
data: KeyValuePair
|
||||
) {
|
||||
return totalcmsUploadAPI(auth, 'image', slug, file, data);
|
||||
}
|
||||
|
||||
export async function saveGallery(
|
||||
auth: TotalCMSAuthType,
|
||||
slug: string,
|
||||
file: FileUpload,
|
||||
data: KeyValuePair
|
||||
) {
|
||||
return totalcmsUploadAPI(auth, 'gallery', slug, file, data);
|
||||
}
|
||||
|
||||
export async function saveBlogImage(
|
||||
auth: TotalCMSAuthType,
|
||||
slug: string,
|
||||
file: FileUpload,
|
||||
data: KeyValuePair
|
||||
) {
|
||||
return totalcmsUploadAPI(auth, 'blog', slug, file, data, 'image');
|
||||
}
|
||||
|
||||
export async function saveBlogGallery(
|
||||
auth: TotalCMSAuthType,
|
||||
slug: string,
|
||||
file: FileUpload,
|
||||
data: KeyValuePair
|
||||
) {
|
||||
return totalcmsUploadAPI(auth, 'blog', slug, file, data, 'gallery');
|
||||
}
|
||||
|
||||
export async function saveContent(
|
||||
auth: TotalCMSAuthType,
|
||||
type: string,
|
||||
slug: string,
|
||||
data: KeyValuePair
|
||||
) {
|
||||
return totalcmsAPI(auth, type, slug, {}, data, HttpMethod.POST);
|
||||
}
|
||||
|
||||
export async function getContent(
|
||||
auth: TotalCMSAuthType,
|
||||
type: string,
|
||||
slug: string,
|
||||
query: QueryParams = {}
|
||||
) {
|
||||
return totalcmsAPI(auth, type, slug, query);
|
||||
}
|
||||
|
||||
export async function getBlogPost(
|
||||
auth: TotalCMSAuthType,
|
||||
slug: string,
|
||||
permalink: string
|
||||
) {
|
||||
return totalcmsAPI(auth, 'blog', slug, { permalink: permalink });
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { AppConnectionValueForAuthProperty, PieceAuth, Property } from '@activepieces/pieces-framework';
|
||||
import { z } from 'zod';
|
||||
import { propsValidation } from '@activepieces/pieces-common';
|
||||
import { saveContent } from './api';
|
||||
import { AppConnectionType } from '@activepieces/shared';
|
||||
|
||||
export type TotalCMSAuthType = AppConnectionValueForAuthProperty<typeof cmsAuth>;
|
||||
|
||||
export const cmsAuth = PieceAuth.CustomAuth({
|
||||
description: 'Setup your Total CMS connection',
|
||||
props: {
|
||||
domain: Property.ShortText({
|
||||
displayName: 'Total CMS Domain',
|
||||
description: 'The domain of your Total CMS website',
|
||||
required: true,
|
||||
}),
|
||||
license: PieceAuth.SecretText({
|
||||
displayName: 'License Key',
|
||||
description: 'The License key for your Total CMS domain',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
required: true,
|
||||
async validate({ auth }) {
|
||||
await propsValidation.validateZod(auth, {
|
||||
domain: z.string().url(),
|
||||
license: z.string(),
|
||||
});
|
||||
|
||||
const response = await saveContent({
|
||||
type: AppConnectionType.CUSTOM_AUTH,
|
||||
props: auth,
|
||||
}, 'text', 'activepieces', {
|
||||
text: 'verified',
|
||||
});
|
||||
if (response.success !== true) {
|
||||
throw new Error(
|
||||
'Authentication failed. Please check your domain and license key and try again.'
|
||||
);
|
||||
}
|
||||
return {
|
||||
valid: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
import {
|
||||
TriggerStrategy,
|
||||
createTrigger,
|
||||
Property,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import {
|
||||
DedupeStrategy,
|
||||
Polling,
|
||||
pollingHelper,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { TotalCMSAuthType, cmsAuth } from '../auth';
|
||||
import { getContent } from '../api';
|
||||
|
||||
const polling: Polling<
|
||||
AppConnectionValueForAuthProperty<typeof cmsAuth>,
|
||||
{ slug: string }
|
||||
> = {
|
||||
strategy: DedupeStrategy.LAST_ITEM,
|
||||
items: async ({ auth, propsValue }) => {
|
||||
const slug = propsValue.slug;
|
||||
const posts = await getContent(auth, 'blog', slug);
|
||||
|
||||
return posts.data.map((post: { permalink: string }) => ({
|
||||
id: post.permalink,
|
||||
data: post,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
export const newBlogPost = createTrigger({
|
||||
name: 'new_blog_post',
|
||||
displayName: 'New Blog Post',
|
||||
description: 'Triggers when a new blog post is published',
|
||||
type: TriggerStrategy.POLLING,
|
||||
props: {
|
||||
slug: Property.ShortText({
|
||||
displayName: 'CMS ID',
|
||||
description: 'The CMS ID of the content to retrieve',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
sampleData: {},
|
||||
onEnable: async (context) => {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth as TotalCMSAuthType,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
onDisable: async (context) => {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth as TotalCMSAuthType,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
run: async (context) => {
|
||||
return await pollingHelper.poll(polling, {
|
||||
auth: context.auth as TotalCMSAuthType,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
files: context.files,
|
||||
});
|
||||
},
|
||||
test: async (context) => {
|
||||
return await pollingHelper.test(polling, {
|
||||
auth: context.auth as TotalCMSAuthType,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
files: context.files,
|
||||
});
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user