import { REDDIT_CONTENT_ID_SCHEMA, REDDIT_CONTENT_PAGE_SCHEMA, REDDIT_JSON_STATUS_SCHEMA, REDDIT_POST_FLAIR_TEMPLATE_SCHEMA, REDDIT_PROVIDER_CONTENT_LISTING_SCHEMA, REDDIT_PROVIDER_FLAIR_TEMPLATE_SCHEMA, REDDIT_SUBREDDIT_NAME_SCHEMA, REDDIT_THING_ID_SCHEMA, toRedditComment, toRedditPageInfo, toRedditPost, } from "@automate.ax/integration-contracts/reddit" import { z } from "zod" import { defineAction } from "../../automation/actions" import { getRedditApi, REDDIT_ACCOUNT, redditAccountRequirement, redditPathSegment, } from "./lib" /** Lists posts and comments awaiting moderator review. */ export const listRedditModQueue = defineAction("List Reddit mod queue") .account(REDDIT_ACCOUNT, redditAccountRequirement("read")) .input( z.object({ after: REDDIT_THING_ID_SCHEMA.optional(), limit: z.number().int().min(1).max(100).prefault(25), only: z.enum(["comments", "links"]).optional(), subreddit: REDDIT_SUBREDDIT_NAME_SCHEMA, }), ) .output(REDDIT_CONTENT_PAGE_SCHEMA) .retry({ replaySafety: "safe" }) .handler(async ({ account, input }) => { const response = await getRedditApi(account.secret).request( `r/${redditPathSegment(input.subreddit)}/about/modqueue`, { query: { after: input.after, limit: input.limit, only: input.only, }, responseSchema: REDDIT_PROVIDER_CONTENT_LISTING_SCHEMA, }, ) return { content: response.data.children.map((thing) => thing.kind === "t3" ? toRedditPost(thing.data) : toRedditComment(thing.data), ), pageInfo: toRedditPageInfo(response), } }) /** Approves a Reddit post or comment and clears its reports. */ export const approveRedditContent = moderationStateAction( "Approve Reddit content", "api/approve", ) /** Removes a Reddit post or comment, optionally as spam. */ export const removeRedditContent = defineAction("Remove Reddit content") .account(REDDIT_ACCOUNT, redditAccountRequirement("modposts")) .input( z.object({ contentId: REDDIT_CONTENT_ID_SCHEMA, spam: z.boolean().prefault(false), }), ) .output(z.void()) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => { await getRedditApi(account.secret).request("api/remove", { body: { id: input.contentId, spam: input.spam }, method: "POST", responseSchema: z.undefined(), }) }) /** Locks a Reddit post or comment. */ export const lockRedditContent = moderationStateAction( "Lock Reddit content", "api/lock", ) /** Unlocks a Reddit post or comment. */ export const unlockRedditContent = moderationStateAction( "Unlock Reddit content", "api/unlock", ) /** Lists post flair templates available to the connected user. */ export const listRedditPostFlairs = defineAction("List Reddit post flairs") .account(REDDIT_ACCOUNT, redditAccountRequirement("flair")) .input(z.object({ subreddit: REDDIT_SUBREDDIT_NAME_SCHEMA })) .output(z.object({ flairs: REDDIT_POST_FLAIR_TEMPLATE_SCHEMA.array() })) .retry({ replaySafety: "safe" }) .handler(async ({ account, input }) => { // Keep the provider template list named for the public field conversion. const flairs = await getRedditApi(account.secret).request( `r/${redditPathSegment(input.subreddit)}/api/link_flair_v2`, { responseSchema: REDDIT_PROVIDER_FLAIR_TEMPLATE_SCHEMA.array() }, ) return { flairs: flairs.map((flair) => ({ backgroundColor: flair.background_color, cssClass: flair.css_class, id: flair.flair_template_id, isEditable: flair.flair_text_editable, text: flair.flair_text, textColor: flair.text_color, })), } }) /** Applies a post flair template and optional editable text. */ export const setRedditPostFlair = defineAction("Set Reddit post flair") .account(REDDIT_ACCOUNT, redditAccountRequirement("flair")) .input( z.object({ flairId: z.string().min(1), postId: z.string().regex(/^t3_[a-z0-9]+$/i), subreddit: REDDIT_SUBREDDIT_NAME_SCHEMA, text: z.string().max(64).optional(), }), ) .output(z.void()) .retry({ replaySafety: "safe" }) .handler(async ({ account, input }) => { await getRedditApi(account.secret).request( `r/${redditPathSegment(input.subreddit)}/api/selectflair`, { body: { api_type: "json", flair_template_id: input.flairId, link: input.postId, text: input.text, }, method: "POST", responseSchema: REDDIT_JSON_STATUS_SCHEMA, }, ) }) /** Builds a one-ID moderation mutation. */ /** * @param label - Public action label. * @param path - Reddit API path. */ function moderationStateAction(label: string, path: string) { return defineAction(label) .account(REDDIT_ACCOUNT, redditAccountRequirement("modposts")) .input(z.object({ contentId: REDDIT_CONTENT_ID_SCHEMA })) .output(z.void()) .retry({ replaySafety: "safe" }) .handler(async ({ account, input }) => { await getRedditApi(account.secret).request(path, { body: { id: input.contentId }, method: "POST", responseSchema: z.undefined(), }) }) }