Files
context-mod/src/Schema/App.json

7253 lines
375 KiB
JSON

{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ActivityState": {
"properties": {
"age": {
"description": "A duration and how to compare it against a value\n\nThe syntax is `(< OR > OR <= OR >=) <number> <unit>` EX `> 100 days`, `<= 2 months`\n\n* EX `> 100 days` => Passes if the date being compared is before 100 days ago\n* EX `<= 2 months` => Passes if the date being compared is after or equal to 2 months\n\nUnit must be one of [DayJS Duration units](https://day.js.org/docs/en/durations/creating)\n\n[See] https://regexr.com/609n8 for example",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(days|weeks|months|years|hours|minutes|seconds|milliseconds)\\s*$",
"type": "string"
},
"approved": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"$ref": "#/definitions/ModeratorNameCriteria"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* true/false => test whether Activity is approved or not\n* string or list of strings => test which moderator approved this Activity"
},
"authorFlairBackgroundColor": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY color\n* If `false` then passes if NO color\n* If string or list of strings then color is matched, case-insensitive, without #. String may also be a regular expression enclosed in forward slashes."
},
"authorFlairCssClass": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY class\n* If `false` then passes if NO class\n* If string or list of strings then class is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"authorFlairTemplateId": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY flair\n* If `false` then passes if NO flair\n* If string or list of strings then template id is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"authorFlairText": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY flair\n* If `false` then passes if NO flair\n* If string or list of strings then text is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"createdOn": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "A relative datetime description to match the date the Activity was created\n\nMay be either:\n\n* day of the week (monday, tuesday, etc...)\n* cron expression IE `* * 15 *`\n\nSee https://crontab.guru/ for generating expressions\n\nhttps://regexr.com/6u3cc"
},
"deleted": {
"type": "boolean"
},
"dispatched": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "Test whether the activity is present in dispatched/delayed activities\n\nNOTE: This is DOES NOT mean that THIS activity is from dispatch -- just that it exists there. To test whether THIS activity is from dispatch use `source`\n\n* `true` => activity exists in delayed activities\n* `false` => activity DOES NOT exist in delayed activities\n* `string` => activity exists in delayed activities with given identifier\n* `string[]` => activity exists in delayed activities with any of the given identifiers"
},
"distinguished": {
"type": "boolean"
},
"filtered": {
"type": "boolean"
},
"locked": {
"type": "boolean"
},
"removed": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"$ref": "#/definitions/ModeratorNameCriteria"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* true/false => test whether Activity is removed or not\n* string or list of strings => test which moderator removed this Activity"
},
"reports": {
"description": "A string containing a comparison operator, a value to compare against, an (optional) report type filter, an (optional) qualifier for report reason, and an (optional) time constraint\n\nThe syntax is `(< OR > OR <= OR >=) number[%] [type] [reasonQualifier] [timeValue] [timeUnit]`\n\nIf only comparison and number is given then defaults to TOTAL reports on an Activity.\n\n* EX `> 2` => greater than 2 total reports\n\nType (optional) determines which type of reports to look at:\n\n* `mod` -- mod reports\n * EX `> 3 mod` => greater than 3 mod reports\n* `user` -- user reports\n * EX `> 3 user` => greater than 3 user reports\n\nReport reason qualifiers can be:\n\n* enclosed double or single quotes -- report reason contains\n * EX `> 1 \"misinformation\" => greater than 1 report with reason containing \"misinformation\"\n* enclosed in backslashes -- match regex\n * EX `> 1 \\harassment towards .*\\` => greater than 1 report with reason matching regex \\harassment towards .*\\\n\nType and reason qualifiers can be used together:\n\nEX `> 2 user \"misinformation\" => greater than 2 user reports with reasons containing \"misinformation\"\n\nThe time constraint filter reports created between NOW and [timeConstraint] in the past:\n\n* `> 3 in 30 minutes` => more than 3 reports created between NOW and 30 minutes ago\n* `> 2 user \"misinformation\" in 2 hours` => more than 2 user reports containing \"misinformation\" created between NOW and 2 hours ago",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)(\\s*%)?(\\s+(?:mods?|users?))?(\\s+(?:[\"'].*[\"']|\\/.*\\/))?.*(\\d+)?\\s*(days?|weeks?|months?|years?|hours?|minutes?|seconds?|milliseconds?)?\\s*$",
"type": "string"
},
"score": {
"description": "A string containing a comparison operator and a value to compare against\n\nThe syntax is `(< OR > OR <= OR >=) <number>`\n\n* EX `> 100` => greater than 100",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"source": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "Test where the current activity was sourced from.\n\nA source can be any of:\n\n* `poll` => activity was retrieved from polling a queue (unmoderated, modqueue, etc...)\n* `poll:[pollSource]` => activity was retrieved from specific polling source IE `poll:unmoderated` activity comes from unmoderated queue\n * valid sources: unmoderated modqueue newComm newSub\n* `dispatch` => activity is from Dispatch Action\n* `dispatch:[identifier]` => activity is from Dispatch Action with specific identifier\n* `user` => activity was from user input (web dashboard)"
},
"spam": {
"type": "boolean"
},
"stickied": {
"type": "boolean"
}
},
"type": "object"
},
"ActivityThreshold": {
"additionalProperties": false,
"description": "At least one count property must be present. If both are present then either can trigger the rule",
"minProperties": 1,
"properties": {
"commentState": {
"$ref": "#/definitions/CommentState",
"description": "When present, a Comment will only be counted if it meets this criteria",
"examples": [
{
"op": true,
"removed": false
}
]
},
"karma": {
"description": "Test the **combined karma** from Activities found in the specified subreddits\n\nValue is a string containing a comparison operator and a number of **combined karma** to compare against\n\nIf specified then both `threshold` and `karma` must be met for this `SubThreshold` to be satisfied\n\nThe syntax is `(< OR > OR <= OR >=) <number>`\n\n* EX `> 50` => greater than 50 combined karma for all found Activities in specified subreddits",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"submissionState": {
"$ref": "#/definitions/SubmissionState",
"description": "When present, a Submission will only be counted if it meets this criteria",
"examples": [
{
"over_18": true,
"removed": false
}
]
},
"subredditThreshold": {
"default": ">= 1",
"description": "A string containing a comparison operator and a value to compare the **number of subreddits that have valid activities** against\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign]`\n\n* EX `> 3` => greater than 3 Subreddits found with valid activities\n* EX `<= 75%` => number of Subreddits with valid activities are equal to or less than 75% of all Subreddits found\n\n**Note:** If you use percentage comparison here as well as `useSubmissionAsReference` then \"all Subreddits found\" is only pertains to Subreddits that had the Link of the Submission, rather than all Subreddits from this window.",
"examples": [
">= 1"
],
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"subreddits": {
"description": "Activities will be counted if they are found in this list of Subreddits\n\nEach value in the list can be either:\n\n * string (name of subreddit)\n * regular expression to run on the subreddit name\n * `SubredditState`\n\nEX `[\"mealtimevideos\",\"askscience\", \"/onlyfans*\\/i\", {\"over18\": true}]`",
"examples": [
[
"mealtimevideos",
"askscience",
"/onlyfans*/i",
{
"over18": true
}
]
],
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubredditCriteria"
},
{
"type": "string"
}
]
},
"type": "array"
},
"threshold": {
"default": ">= 1",
"description": "A string containing a comparison operator and a value to compare recent activities against\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign]`\n\n* EX `> 3` => greater than 3 activities found in the listed subreddits\n* EX `<= 75%` => number of Activities in the subreddits listed are equal to or less than 75% of all Activities\n\n**Note:** If you use percentage comparison here as well as `useSubmissionAsReference` then \"all Activities\" is only pertains to Activities that had the Link of the Submission, rather than all Activities from this window.",
"examples": [
">= 1"
],
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
}
},
"type": "object"
},
"ApproveActionJson": {
"description": "Ban the Author of the Activity this Check is run on",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"approve"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"targets": {
"description": "Specify which Activities to approve\n\nThis setting is only applicable if the Activity being acted on is a **comment**. On a **submission** the setting does nothing\n\n* self => approve activity being checked (comment)\n* parent => approve parent (submission) of activity being checked (comment)",
"items": {
"enum": [
"parent",
"self"
],
"type": "string"
},
"type": "array"
}
},
"required": [
"kind"
],
"type": "object"
},
"AttributionCriteria": {
"properties": {
"aggregateOn": {
"default": "undefined",
"description": "This list determines which categories of domains should be aggregated on. All aggregated domains will be tested against `threshold`\n\n* If `media` is included then aggregate author's submission history which reddit recognizes as media (youtube, vimeo, etc.)\n* If `redditMedia` is included then aggregate on author's submissions history which are media hosted on reddit: galleries, videos, and images (i.redd.it / v.redd.it)\n* If `self` is included then aggregate on author's submission history which are self-post (`self.[subreddit]`) or domain is `reddit.com`\n* If `link` is included then aggregate author's submission history which is external links and not recognized as `media` by reddit\n\nIf nothing is specified or list is empty (default) rule will only aggregate on `link` and `media` (ignores reddit-hosted content and self-posts)",
"examples": [
[]
],
"items": {
"enum": [
"link",
"media",
"redditMedia",
"self"
],
"type": "string"
},
"type": "array"
},
"commentState": {
"$ref": "#/definitions/CommentState",
"deprecationMessage": "use `window.filterOn.post.commentState` instead",
"description": "DEPRECATED - use `window.filterOn.post.commentState` instead\n\nWhen present, Comments from `window` will only be counted if they meet this criteria",
"examples": [
{
"op": true,
"removed": false
}
]
},
"consolidateMediaDomains": {
"default": false,
"description": "Should the criteria consolidate recognized media domains into the parent domain?\n\nSubmissions to major media domains (youtube, vimeo) can be identified by individual Channel/Author...\n\n* If `false` then domains will be aggregated at the channel level IE Youtube Channel A (2 counts), Youtube Channel B (3 counts)\n* If `true` then then media domains will be consolidated at domain level and then aggregated IE youtube.com (5 counts)",
"examples": [
false
],
"type": "boolean"
},
"domains": {
"default": [
[]
],
"description": "A list of domains whose Activities will be tested against `threshold`.\n\nThe values are tested as partial strings so you do not need to include full URLs, just the part that matters.\n\nEX `[\"youtube\"]` will match submissions with the domain `https://youtube.com/c/aChannel`\nEX `[\"youtube.com/c/bChannel\"]` will NOT match submissions with the domain `https://youtube.com/c/aChannel`\n\nIf you wish to aggregate on self-posts for a subreddit use the syntax `self.[subreddit]` EX `self.AskReddit`\n\n**If this Rule is part of a Check for a Submission and you wish to aggregate on the domain of the Submission use the special string `AGG:SELF`**\n\nIf nothing is specified or list is empty (default) aggregate using `aggregateOn`",
"items": {
"type": "string"
},
"type": "array"
},
"domainsCombined": {
"default": false,
"description": "Set to `true` if you wish to combine all of the Activities from `domains` to test against `threshold` instead of testing each `domain` individually",
"examples": [
false
],
"type": "boolean"
},
"exclude": {
"deprecationMessage": "use `window.filterOn.post.subreddits` instead",
"description": "DEPRECATED - use `window.filterOn.post.subreddits` instead\n\nWhen present, Activities WILL NOT be counted if they are found in this list of Subreddits\n\nEach value in the list can be either:\n\n * string (name of subreddit)\n * regular expression to run on the subreddit name\n * `SubredditState`\n\nEX `[\"mealtimevideos\",\"askscience\", \"/onlyfans*\\/i\", {\"over18\": true}]`",
"examples": [
[
"mealtimevideos",
"askscience",
"/onlyfans*/i",
{
"over18": true
}
]
],
"items": {
"type": "string"
},
"type": "array"
},
"include": {
"deprecationMessage": "use `window.filterOn.post.subreddits` instead",
"description": "DEPRECATED - use `window.filterOn.post.subreddits` instead\n\nWhen present, Activities WILL ONLY be counted if they are found in this list of Subreddits\n\nEach value in the list can be either:\n\n * string (name of subreddit)\n * regular expression to run on the subreddit name\n * `SubredditState`\n\nEX `[\"mealtimevideos\",\"askscience\", \"/onlyfans*\\/i\", {\"over18\": true}]`",
"examples": [
[
"mealtimevideos",
"askscience",
"/onlyfans*/i",
{
"over18": true
}
]
],
"items": {
"type": "string"
},
"type": "array"
},
"minActivityCount": {
"default": 5,
"description": "The minimum number of activities that must exist for this criteria to run",
"type": "number"
},
"name": {
"type": "string"
},
"submissionState": {
"$ref": "#/definitions/SubmissionState",
"deprecationMessage": "use `window.filterOn.post.submissionState` instead",
"description": "When present, Submissions from `window` will only be counted if they meet this criteria",
"examples": [
{
"over_18": true,
"removed": false
}
]
},
"threshold": {
"default": "> 10%",
"description": "A string containing a comparison operator and a value to compare comments against\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign]`\n\n* EX `> 12` => greater than 12 activities originate from same attribution\n* EX `<= 10%` => less than 10% of all Activities have the same attribution",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"thresholdOn": {
"default": "all",
"deprecationMessage": "use `window.fetch` instead",
"description": "DEPRECATED -- use `window.fetch` instead\n\nWhat activities to use for total count when determining what percentage an attribution comprises\n\nEX:\n\nAuthor has 100 activities, 40 are submissions and 60 are comments\n\n* If `submission` then if 10 submission are for Youtube Channel A then percentage => 10/40 = 25%\n* If `all` then if 10 submission are for Youtube Channel A then percentage => 10/100 = 10%",
"enum": [
"all",
"submissions"
],
"type": "string"
},
"window": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"$ref": "#/definitions/FullActivityWindowConfig"
},
{
"type": [
"string",
"number"
]
}
],
"description": "A value to define the range of Activities to retrieve.\n\nAcceptable values:\n\n**`ActivityWindowCriteria` object**\n\nAllows specify multiple range properties and more specific behavior\n\n**A `number` of Activities to retrieve**\n\n* EX `100` => 100 Activities\n\n*****\n\nAny of the below values that specify the amount of time to subtract from `NOW` to create a time range IE `NOW <---> [duration] ago`\n\nAcceptable values:\n\n**A `string` consisting of a value and a [Day.js](https://day.js.org/docs/en/durations/creating#list-of-all-available-units) time UNIT**\n\n* EX `9 days` => Range is `NOW <---> 9 days ago`\n\n**A [Day.js](https://day.js.org/docs/en/durations/creating) `object`**\n\n* EX `{\"days\": 90, \"minutes\": 15}` => Range is `NOW <---> 90 days and 15 minutes ago`\n\n**An [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) `string`**\n\n* EX `PT15M` => 15 minutes => Range is `NOW <----> 15 minutes ago`",
"examples": [
"90 days"
]
}
},
"required": [
"threshold",
"window"
],
"type": "object"
},
"AttributionJSONConfig": {
"description": "Aggregates all of the domain/media accounts attributed to an author's Submission history. If any domain is over the threshold the rule is triggered\n\nAvailable data for [Action templating](https://github.com/FoxxMD/context-mod#action-templating):\n\n```\ntriggeredDomainCount => Number of domains that met the threshold\nactivityTotal => Number of Activities considered from window\nwindow => The date range of the Activities considered\nlargestCount => The count from the largest aggregated domain\nlargestPercentage => The percentage of Activities the largest aggregated domain comprises\nsmallestCount => The count from the smallest aggregated domain\nsmallestPercentage => The percentage of Activities the smallest aggregated domain comprises\ncountRange => A convenience string displaying \"smallestCount - largestCount\" or just one number if both are the same\npercentRange => A convenience string displaying \"smallestPercentage - largestPercentage\" or just one percentage if both are the same\ndomains => An array of all the domain URLs that met the threshold\ndomainsDelim => A comma-delimited string of all the domain URLs that met the threshold\ntitles => The friendly-name of the domain if one is present, otherwise the URL (IE youtube.com/c/34ldfa343 => \"My Youtube Channel Title\")\ntitlesDelim => A comma-delimited string of all the domain friendly-names\nthreshold => The threshold you configured for this Rule to trigger\nurl => Url of the submission that triggered the rule\n```",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"criteria": {
"description": "A list threshold-window values to test attribution against\n\nIf none is provided the default set used is:\n\n```\nthreshold: 10%\nwindow: 100\n```",
"items": {
"$ref": "#/definitions/AttributionCriteria"
},
"minItems": 1,
"type": "array"
},
"criteriaJoin": {
"description": "* If `OR` then any set of AttributionCriteria that produce an Attribution over the threshold will trigger the rule.\n* If `AND` then all AttributionCriteria sets must product an Attribution over the threshold to trigger the rule.",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The kind of rule to run",
"enum": [
"attribution"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this rule. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes\n\nname is used to reference Rule result data during Action content templating. See CommentAction or ReportAction for more details.",
"examples": [
"myNewRule"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"AuthorCriteria": {
"additionalProperties": false,
"description": "Criteria with which to test against the author of an Activity. The outcome of the test is based on:\n\n1. All present properties passing and\n2. If a property is a list then any value from the list matching",
"examples": [
{
"flairText": [
"Contributor",
"Veteran"
],
"isMod": true,
"name": [
"FoxxMD",
"AnotherUser"
]
}
],
"minProperties": 1,
"properties": {
"age": {
"description": "Test the age of the Author's account (when it was created) against this comparison\n\nThe syntax is `(< OR > OR <= OR >=) <number> <unit>`\n\n* EX `> 100 days` => Passes if Author's account is older than 100 days\n* EX `<= 2 months` => Passes if Author's account is younger than or equal to 2 months\n\nUnit must be one of [DayJS Duration units](https://day.js.org/docs/en/durations/creating)\n\n[See] https://regexr.com/609n8 for example",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(days?|weeks?|months?|years?|hours?|minutes?|seconds?|milliseconds?)\\s*$",
"type": "string"
},
"commentKarma": {
"description": "A string containing a comparison operator and a value to compare karma against\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign]`\n\n* EX `> 100` => greater than 100 comment karma\n* EX `<= 75%` => comment karma is less than or equal to 75% of **all karma**",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"description": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "An (array of) string/regular expression to test contents of an Author's profile description against\n\nIf no flags are specified then the **insensitive** flag is used by default\n\nIf using an array then if **any** value in the array passes the description test passes",
"examples": [
[
"/test$/i",
"look for this string literal"
]
]
},
"flairBackgroundColor": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "The (user) flair background color (or list of) from the subreddit to match against\n\n* If `true` then passes if ANY css background color is assigned\n* If `false` then passes if NO css background is assigned\n* If string or list of strings then color is matched, case-insensitive, without #. String may also be a regular expression enclosed in forward slashes."
},
"flairCssClass": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "A (user) flair css class (or list of) from the subreddit to match against\n\n* If `true` then passes if ANY css is assigned\n* If `false` then passes if NO css is assigned\n* If string or list of strings then text is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes.",
"examples": [
"red"
]
},
"flairTemplate": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "A (user) flair template id (or list of) from the subreddit to match against\n\n* If `true` then passes if ANY template is assigned\n* If `false` then passed if NO template is assigned\n* If string or list of strings then text is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"flairText": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "A (user) flair text value (or list of) from the subreddit to match against\n\n* If `true` then passes if ANY text is assigned\n* If `false` then passes if NO text is assigned\n* If string or list of strings then text is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes.",
"examples": [
"Approved"
]
},
"isContributor": {
"description": "Is the author an approved user (contributor)?",
"type": "boolean"
},
"isMod": {
"description": "Is the author a moderator?",
"type": "boolean"
},
"linkKarma": {
"description": "A string containing a comparison operator and a value to compare link karma against\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign]`\n\n* EX `> 100` => greater than 100 link karma\n* EX `<= 75%` => link karma is less than or equal to 75% of **all karma**",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"modActions": {
"items": {
"anyOf": [
{
"$ref": "#/definitions/ModNoteCriteria"
},
{
"$ref": "#/definitions/ModLogCriteria"
}
]
},
"type": "array"
},
"name": {
"description": "A list of reddit usernames (case-insensitive) or regular expressions to match against. Do not include the \"u/\" prefix\n\n\n EX to match against /u/FoxxMD and /u/AnotherUser use [\"FoxxMD\",\"AnotherUser\"]",
"examples": [
"FoxxMD",
"AnotherUser",
"/.*Foxx./*i"
],
"items": {
"type": "string"
},
"type": "array"
},
"shadowBanned": {
"description": "Is the author shadowbanned?\n\nThis is determined by trying to retrieve the author's profile. If a 404 is returned it is likely they are shadowbanned",
"type": "boolean"
},
"totalKarma": {
"description": "A string containing a comparison operator and a value to compare against\n\nThe syntax is `(< OR > OR <= OR >=) <number>`\n\n* EX `> 100` => greater than 100",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"userNotes": {
"description": "A list of UserNote properties to check against the User Notes attached to this Author in this Subreddit (must have Toolbox enabled and used User Notes at least once)",
"items": {
"$ref": "#/definitions/UserNoteCriteria"
},
"type": "array"
},
"verified": {
"description": "Does Author's account have a verified email?",
"type": "boolean"
}
},
"type": "object"
},
"AuthorRuleJSONConfig": {
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"exclude": {
"description": "Only runs if include is not present. Will \"pass\" if any of set of the AuthorCriteria does not pass",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
}
]
},
"type": "array"
},
"include": {
"description": "Will \"pass\" if any set of AuthorCriteria passes",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
}
]
},
"type": "array"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The kind of rule to run",
"enum": [
"author"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this rule. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes\n\nname is used to reference Rule result data during Action content templating. See CommentAction or ReportAction for more details.",
"examples": [
"myNewRule"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"BanActionJson": {
"description": "Ban the Author of the Activity this Check is run on",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"duration": {
"description": "Number of days to ban the Author. If not specified Author will be banned permanently.",
"examples": [
90
],
"maximum": 999,
"minimum": 1,
"type": "number"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"footer": {
"anyOf": [
{
"enum": [
false
],
"type": "boolean"
},
{
"type": "string"
}
],
"description": "Customize the footer for Actions that send replies (Comment/Ban)\n\nIf `false` no footer is appended\n\nIf `string` the value is rendered as markdown or will use `wiki:` parser the same way `content` properties on Actions are rendered with [templating](https://github.com/FoxxMD/context-mod#action-templating).\n\nIf footer is `undefined` (not set) the default footer will be used:\n\n> *****\n> This action was performed by [a bot.] Mention a moderator or [send a modmail] if you any ideas, questions, or concerns about this action.\n\n*****\n\nThe following properties are available for [templating](https://github.com/FoxxMD/context-mod#action-templating):\n```\nsubName => name of subreddit Action was performed in (EX 'mealtimevideos')\npermaLink => The permalink for the Activity the Action was performed on EX https://reddit.com/r/yourSub/comments/o1h0i0/title_name/1v3b7x\nmodmaiLink => An encoded URL that will open a new message to your subreddit with the Action permalink appended to the body\nbotLink => A permalink to the FAQ for this bot.\n```\nIf you use your own footer or no footer **please link back to the bot FAQ** using the `{{botLink}}` property in your content :)"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"ban"
],
"type": "string"
},
"message": {
"description": "The message that is sent in the ban notification. `message` is interpreted as reddit-flavored Markdown.\n\nIf value starts with `wiki:` then the proceeding value will be used to get a wiki page\n\nEX `wiki:botconfig/mybot` tries to get `https://reddit.com/mySubredditExample/wiki/botconfig/mybot`\n\nEX `this is plain text` => \"this is plain text\"\n\nEX `this is **bold** markdown text` => \"this is **bold** markdown text\"",
"examples": [
"This is the content of a comment/report/usernote",
"this is **bold** markdown text",
"wiki:botconfig/acomment"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"note": {
"description": "A mod note for this ban. Can use Templating.\n\nIf the length expands to more than 100 characters it will truncated with \"...\"",
"examples": [
"Sock puppet for u/AnotherUser"
],
"type": "string"
},
"reason": {
"description": "Reason for ban. Can use Templating.\n\nIf the length expands to more than 100 characters it will truncated with \"...\"",
"examples": [
"repeat spam"
],
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"CacheConfig": {
"properties": {
"authorTTL": {
"default": 60,
"description": "Amount of time, in seconds, author activity history (Comments/Submission) should be cached\n\n* If `0` or `true` will cache indefinitely (not recommended)\n* If `false` will not cache\n\n* ENV => `AUTHOR_TTL`\n* ARG => `--authorTTL <sec>`",
"examples": [
60
],
"type": [
"number",
"boolean"
]
},
"commentTTL": {
"default": 60,
"description": "Amount of time, in seconds, a comment should be cached\n\n* If `0` or `true` will cache indefinitely (not recommended)\n* If `false` will not cache",
"examples": [
60
],
"type": [
"number",
"boolean"
]
},
"filterCriteriaTTL": {
"default": 60,
"description": "Amount of time, in seconds, to cache filter criteria results (`authorIs` and `itemIs` results)\n\nThis is especially useful if when polling high-volume comments and your checks rely on author/item filters\n\n* If `0` or `true` will cache indefinitely (not recommended)\n* If `false` will not cache",
"examples": [
60
],
"type": [
"number",
"boolean"
]
},
"modNotesTTL": {
"default": 60,
"description": "Amount of time, in seconds, Mod Notes should be cached\n\n* If `0` or `true` will cache indefinitely (not recommended)\n* If `false` will not cache",
"examples": [
60
],
"type": [
"number",
"boolean"
]
},
"provider": {
"anyOf": [
{
"$ref": "#/definitions/CacheOptions"
},
{
"enum": [
"memory",
"none",
"redis"
],
"type": "string"
}
],
"description": "The cache provider and, optionally, a custom configuration for that provider\n\nIf not present or `null` provider will be `memory`.\n\nTo specify another `provider` but use its default configuration set this property to a string of one of the available providers: `memory`, `redis`, or `none`"
},
"selfTTL": {
"default": 50,
"description": "Amount of time, in seconds, an Activity that the bot has acted on or created will be ignored if found during polling\n\nThis is useful to prevent the bot from checking Activities it *just* worked on or a product of the checks. Examples:\n\n* Ignore comments created through an Action\n* Ignore Activity polled from modqueue that the bot just reported\n\nThis value should be at least as long as the longest polling interval for modqueue/newComm\n\n* If `0` or `true` will cache indefinitely (not recommended)\n* If `false` will not cache",
"examples": [
50
],
"type": [
"number",
"boolean"
]
},
"submissionTTL": {
"default": 60,
"description": "Amount of time, in seconds, a submission should be cached\n\n* If `0` or `true` will cache indefinitely (not recommended)\n* If `false` will not cache",
"examples": [
60
],
"type": [
"number",
"boolean"
]
},
"subredditTTL": {
"default": 600,
"description": "Amount of time, in seconds, a subreddit (attributes) should be cached\n\n* If `0` or `true` will cache indefinitely (not recommended)\n* If `false` will not cache",
"examples": [
600
],
"type": [
"number",
"boolean"
]
},
"userNotesTTL": {
"default": 300,
"description": "Amount of time, in seconds, [Toolbox User Notes](https://www.reddit.com/r/toolbox/wiki/docs/usernotes) should be cached\n\n* If `0` or `true` will cache indefinitely (not recommended)\n* If `false` will not cache",
"examples": [
300
],
"type": [
"number",
"boolean"
]
},
"wikiTTL": {
"default": 300,
"description": "Amount of time, in seconds, wiki content pages should be cached\n\n* If `0` or `true` will cache indefinitely (not recommended)\n* If `false` will not cache",
"examples": [
300
],
"type": [
"number",
"boolean"
]
}
},
"type": "object"
},
"CacheOptions": {
"additionalProperties": {},
"description": "Configure granular settings for a cache provider with this object",
"properties": {
"auth_pass": {
"description": "(`redis`) the authentication passphrase (if enabled)",
"type": "string"
},
"db": {
"default": 0,
"description": "(`redis`) the db number to use",
"examples": [
0
],
"type": "number"
},
"host": {
"default": "localhost",
"description": "(`redis`) hostname",
"examples": [
"localhost"
],
"type": "string"
},
"max": {
"default": 500,
"description": "(`memory`) The maximum number of keys (unique cache calls) to store in cache\n\nWhen the maximum number of keys is reached the cache will being dropping the [least-recently-used](https://github.com/isaacs/node-lru-cache) key to keep the cache at `max` size.\n\nThis will determine roughly how large in **RAM** each `memory` cache can be, based on how large your `window` criteria are. Consider this example:\n\n* all `window` criteria in a subreddit's rules are `\"window\": 100`\n* `\"max\": 500`\n* Maximum size of **each** memory cache will be `500 x 100 activities = 50,000 activities`\n * So the shared cache would be max 50k activities and\n * Every additional private cache (when a subreddit configures their cache separately) will also be max 50k activities",
"examples": [
500
],
"type": "number"
},
"port": {
"default": 6379,
"description": "(`redis`) port to connect on",
"examples": [
6379
],
"type": "number"
},
"prefix": {
"description": "A prefix to add to all keys",
"type": "string"
},
"store": {
"$ref": "#/definitions/CacheProvider"
},
"ttl": {
"default": 60,
"description": "The default TTL, in seconds, for the cache provider.\n\nCan mostly be ignored since TTLs are defined for each cache object",
"examples": [
60
],
"type": "number"
}
},
"required": [
"store"
],
"type": "object"
},
"CacheProvider": {
"description": "Available cache providers",
"enum": [
"memory",
"none",
"redis"
],
"type": "string"
},
"CancelDispatchActionJson": {
"description": "Remove the Activity",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"identifier": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"null",
"string"
]
}
]
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"cancelDispatch"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"target": {
"anyOf": [
{
"items": {
"enum": [
"any",
"parent",
"self"
],
"type": "string"
},
"type": "array"
},
{
"enum": [
"any",
"parent",
"self"
],
"type": "string"
}
]
}
},
"required": [
"kind",
"target"
],
"type": "object"
},
"CommentActionJson": {
"description": "Reply to the Activity. For a submission the reply will be a top-level comment.",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"content": {
"description": "The Content to submit for this Action. Content is interpreted as reddit-flavored Markdown.\n\nIf value starts with `wiki:` then the proceeding value will be used to get a wiki page from the current subreddit\n\n * EX `wiki:botconfig/mybot` tries to get `https://reddit.com/r/currentSubreddit/wiki/botconfig/mybot`\n\nIf the value starts with `wiki:` and ends with `|someValue` then `someValue` will be used as the base subreddit for the wiki page\n\n* EX `wiki:replytemplates/test|ContextModBot` tries to get `https://reddit.com/r/ContextModBot/wiki/replytemplates/test`\n\nIf the value starts with `url:` then the value is fetched as an external url and expects raw text returned\n\n* EX `url:https://pastebin.com/raw/38qfL7mL` tries to get the text response of `https://pastebin.com/raw/38qfL7mL`\n\nIf none of the above is used the value is treated as the raw context\n\n * EX `this is **bold** markdown text` => \"this is **bold** markdown text\"\n\nAll Content is rendered using [mustache](https://github.com/janl/mustache.js/#templates) to enable [Action Templating](https://github.com/FoxxMD/context-mod#action-templating).\n\nThe following properties are always available in the template (view individual Rules to see rule-specific template data):\n```\nitem.kind => The type of Activity that was checked (comment/submission)\nitem.author => The name of the Author of the Activity EX FoxxMD\nitem.permalink => A permalink URL to the Activity EX https://reddit.com/r/yourSub/comments/o1h0i0/title_name/1v3b7x\nitem.url => If the Activity is Link Sumbission then the external URL\nitem.title => If the Activity is a Submission then the title of that Submission\nrules => An object containing RuleResults of all the rules run for this check. See Action Templating for more details on naming\n```",
"type": "string"
},
"distinguish": {
"description": "Distinguish the comment after creation?",
"type": "boolean"
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"footer": {
"anyOf": [
{
"enum": [
false
],
"type": "boolean"
},
{
"type": "string"
}
],
"description": "Customize the footer for Actions that send replies (Comment/Ban)\n\nIf `false` no footer is appended\n\nIf `string` the value is rendered as markdown or will use `wiki:` parser the same way `content` properties on Actions are rendered with [templating](https://github.com/FoxxMD/context-mod#action-templating).\n\nIf footer is `undefined` (not set) the default footer will be used:\n\n> *****\n> This action was performed by [a bot.] Mention a moderator or [send a modmail] if you any ideas, questions, or concerns about this action.\n\n*****\n\nThe following properties are available for [templating](https://github.com/FoxxMD/context-mod#action-templating):\n```\nsubName => name of subreddit Action was performed in (EX 'mealtimevideos')\npermaLink => The permalink for the Activity the Action was performed on EX https://reddit.com/r/yourSub/comments/o1h0i0/title_name/1v3b7x\nmodmaiLink => An encoded URL that will open a new message to your subreddit with the Action permalink appended to the body\nbotLink => A permalink to the FAQ for this bot.\n```\nIf you use your own footer or no footer **please link back to the bot FAQ** using the `{{botLink}}` property in your content :)"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"comment"
],
"type": "string"
},
"lock": {
"description": "Lock the comment after creation?",
"type": "boolean"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"sticky": {
"description": "Stick the comment after creation?",
"type": "boolean"
},
"targets": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "Specify where this comment should be made\n\nValid values: 'self' | 'parent' | [reddit permalink]\n\n'self' and 'parent' are special targets that are relative to the Activity being processed:\n* When Activity is Submission => 'parent' does nothing\n* When Activity is Comment\n * 'self' => reply to Activity\n * 'parent' => make a top-level comment in the Submission the Comment is in\n\nIf target is not self/parent then CM assumes the value is a reddit permalink and will attempt to make a comment to that Activity"
}
},
"required": [
"content",
"kind"
],
"type": "object"
},
"CommentCheckConfigData": {
"properties": {
"actions": {
"description": "The `Actions` to run after the check is successfully triggered. ALL `Actions` will run in the order they are listed\n\n Can be `Action` or the `name` of any **named** `Action` in your subreddit's configuration",
"examples": [
[
{
"content": "this is the content of the comment",
"distinguish": true,
"kind": "comment"
},
{
"kind": "lock"
}
]
],
"items": {
"anyOf": [
{
"$ref": "#/definitions/IncludesData"
},
{
"$ref": "#/definitions/FlairActionJson"
},
{
"$ref": "#/definitions/UserFlairActionJson"
},
{
"$ref": "#/definitions/CommentActionJson"
},
{
"$ref": "#/definitions/ReportActionJson"
},
{
"$ref": "#/definitions/LockActionJson"
},
{
"$ref": "#/definitions/RemoveActionJson"
},
{
"$ref": "#/definitions/UserNoteActionJson"
},
{
"$ref": "#/definitions/ApproveActionJson"
},
{
"$ref": "#/definitions/BanActionJson"
},
{
"$ref": "#/definitions/MessageActionJson"
},
{
"$ref": "#/definitions/DispatchActionJson"
},
{
"$ref": "#/definitions/CancelDispatchActionJson"
},
{
"$ref": "#/definitions/ContributorActionJson"
},
{
"$ref": "#/definitions/ModNoteActionJson"
},
{
"$ref": "#/definitions/SubmissionActionJson"
},
{
"type": "string"
}
]
},
"type": "array"
},
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"cacheUserResult": {
"$ref": "#/definitions/UserResultCacheOptions",
"description": "Cache the result of this check based on the comment author and the submission id\n\nThis is useful in this type of scenario:\n\n1. This check is configured to run on comments for specific submissions with high volume activity\n2. The rules being run are not dependent on the content of the comment\n3. The rule results are not likely to change while cache is valid"
},
"condition": {
"default": "AND",
"description": "Under what condition should a set of run `Rule` objects be considered \"successful\"?\n\nIf `OR` then **any** triggered `Rule` object results in success.\n\nIf `AND` then **all** `Rule` objects must be triggered to result in success.",
"enum": [
"AND",
"OR"
],
"examples": [
"AND"
],
"type": "string"
},
"description": {
"examples": [
"A short description of what this check looks for and actions it performs"
],
"type": "string"
},
"dryRun": {
"description": "Use this option to override the `dryRun` setting for all of its `Actions`",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "Should this check be run by the bot?",
"examples": [
true
],
"type": "boolean"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of event (new submission or new comment) this check should be run against",
"enum": [
"comment"
],
"type": "string"
},
"name": {
"description": "Friendly name for this Check EX \"crosspostSpamCheck\"\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myNewCheck"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"notifyOnTrigger": {
"default": false,
"description": "If notifications are configured and this is `true` then an `eventActioned` event will be sent when this check is triggered.",
"type": "boolean"
},
"postFail": {
"anyOf": [
{
"$ref": "#/definitions/PostBehaviorOptionConfig"
},
{
"type": "string"
}
],
"default": "next",
"description": "Do this behavior if a Check is NOT triggered"
},
"postTrigger": {
"anyOf": [
{
"$ref": "#/definitions/PostBehaviorOptionConfig"
},
{
"type": "string"
}
],
"default": "nextRun",
"description": "Do this behavior if a Check is triggered"
},
"rules": {
"description": "A list of Rules to run.\n\nIf `Rule` objects are triggered based on `condition` then `actions` will be performed.\n\nCan be `Rule`, `RuleSet`, or the `name` of any **named** `Rule` in your subreddit's configuration.\n\n**If `rules` is an empty array or not present then `actions` are performed immediately.**",
"items": {
"anyOf": [
{
"$ref": "#/definitions/IncludesData"
},
{
"$ref": "#/definitions/RecentActivityRuleJSONConfig"
},
{
"$ref": "#/definitions/RepeatActivityJSONConfig"
},
{
"$ref": "#/definitions/AuthorRuleJSONConfig"
},
{
"$ref": "#/definitions/AttributionJSONConfig"
},
{
"$ref": "#/definitions/HistoryJSONConfig"
},
{
"$ref": "#/definitions/RegexRuleJSONConfig"
},
{
"$ref": "#/definitions/RepostRuleJSONConfig"
},
{
"$ref": "#/definitions/SentimentRuleJSONConfig"
},
{
"$ref": "#/definitions/MHSRuleJSONConfig"
},
{
"$ref": "#/definitions/RuleSetConfigData"
},
{
"type": "string"
}
]
},
"type": "array"
}
},
"required": [
"kind",
"name"
],
"type": "object"
},
"CommentState": {
"description": "Different attributes a `Comment` can be in. Only include a property if you want to check it.",
"examples": [
{
"op": true,
"removed": false
}
],
"properties": {
"age": {
"description": "A duration and how to compare it against a value\n\nThe syntax is `(< OR > OR <= OR >=) <number> <unit>` EX `> 100 days`, `<= 2 months`\n\n* EX `> 100 days` => Passes if the date being compared is before 100 days ago\n* EX `<= 2 months` => Passes if the date being compared is after or equal to 2 months\n\nUnit must be one of [DayJS Duration units](https://day.js.org/docs/en/durations/creating)\n\n[See] https://regexr.com/609n8 for example",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(days|weeks|months|years|hours|minutes|seconds|milliseconds)\\s*$",
"type": "string"
},
"approved": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"$ref": "#/definitions/ModeratorNameCriteria"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* true/false => test whether Activity is approved or not\n* string or list of strings => test which moderator approved this Activity"
},
"authorFlairBackgroundColor": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY color\n* If `false` then passes if NO color\n* If string or list of strings then color is matched, case-insensitive, without #. String may also be a regular expression enclosed in forward slashes."
},
"authorFlairCssClass": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY class\n* If `false` then passes if NO class\n* If string or list of strings then class is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"authorFlairTemplateId": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY flair\n* If `false` then passes if NO flair\n* If string or list of strings then template id is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"authorFlairText": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY flair\n* If `false` then passes if NO flair\n* If string or list of strings then text is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"createdOn": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "A relative datetime description to match the date the Activity was created\n\nMay be either:\n\n* day of the week (monday, tuesday, etc...)\n* cron expression IE `* * 15 *`\n\nSee https://crontab.guru/ for generating expressions\n\nhttps://regexr.com/6u3cc"
},
"deleted": {
"type": "boolean"
},
"depth": {
"description": "The (nested) level of a comment.\n\n* 0 mean the comment is at top-level (replying to submission)\n* non-zero, Nth value means the comment has N parent comments",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(days|weeks|months|years|hours|minutes|seconds|milliseconds)\\s*$",
"type": "string"
},
"dispatched": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "Test whether the activity is present in dispatched/delayed activities\n\nNOTE: This is DOES NOT mean that THIS activity is from dispatch -- just that it exists there. To test whether THIS activity is from dispatch use `source`\n\n* `true` => activity exists in delayed activities\n* `false` => activity DOES NOT exist in delayed activities\n* `string` => activity exists in delayed activities with given identifier\n* `string[]` => activity exists in delayed activities with any of the given identifiers"
},
"distinguished": {
"type": "boolean"
},
"filtered": {
"type": "boolean"
},
"locked": {
"type": "boolean"
},
"op": {
"description": "Is this Comment Author also the Author of the Submission this comment is in?",
"type": "boolean"
},
"removed": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"$ref": "#/definitions/ModeratorNameCriteria"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* true/false => test whether Activity is removed or not\n* string or list of strings => test which moderator removed this Activity"
},
"reports": {
"description": "A string containing a comparison operator, a value to compare against, an (optional) report type filter, an (optional) qualifier for report reason, and an (optional) time constraint\n\nThe syntax is `(< OR > OR <= OR >=) number[%] [type] [reasonQualifier] [timeValue] [timeUnit]`\n\nIf only comparison and number is given then defaults to TOTAL reports on an Activity.\n\n* EX `> 2` => greater than 2 total reports\n\nType (optional) determines which type of reports to look at:\n\n* `mod` -- mod reports\n * EX `> 3 mod` => greater than 3 mod reports\n* `user` -- user reports\n * EX `> 3 user` => greater than 3 user reports\n\nReport reason qualifiers can be:\n\n* enclosed double or single quotes -- report reason contains\n * EX `> 1 \"misinformation\" => greater than 1 report with reason containing \"misinformation\"\n* enclosed in backslashes -- match regex\n * EX `> 1 \\harassment towards .*\\` => greater than 1 report with reason matching regex \\harassment towards .*\\\n\nType and reason qualifiers can be used together:\n\nEX `> 2 user \"misinformation\" => greater than 2 user reports with reasons containing \"misinformation\"\n\nThe time constraint filter reports created between NOW and [timeConstraint] in the past:\n\n* `> 3 in 30 minutes` => more than 3 reports created between NOW and 30 minutes ago\n* `> 2 user \"misinformation\" in 2 hours` => more than 2 user reports containing \"misinformation\" created between NOW and 2 hours ago",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)(\\s*%)?(\\s+(?:mods?|users?))?(\\s+(?:[\"'].*[\"']|\\/.*\\/))?.*(\\d+)?\\s*(days?|weeks?|months?|years?|hours?|minutes?|seconds?|milliseconds?)?\\s*$",
"type": "string"
},
"score": {
"description": "A string containing a comparison operator and a value to compare against\n\nThe syntax is `(< OR > OR <= OR >=) <number>`\n\n* EX `> 100` => greater than 100",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"source": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "Test where the current activity was sourced from.\n\nA source can be any of:\n\n* `poll` => activity was retrieved from polling a queue (unmoderated, modqueue, etc...)\n* `poll:[pollSource]` => activity was retrieved from specific polling source IE `poll:unmoderated` activity comes from unmoderated queue\n * valid sources: unmoderated modqueue newComm newSub\n* `dispatch` => activity is from Dispatch Action\n* `dispatch:[identifier]` => activity is from Dispatch Action with specific identifier\n* `user` => activity was from user input (web dashboard)"
},
"spam": {
"type": "boolean"
},
"stickied": {
"type": "boolean"
},
"submissionState": {
"description": "A list of SubmissionState attributes to test the Submission this comment is in",
"items": {
"$ref": "#/definitions/SubmissionState"
},
"type": "array"
}
},
"type": "object"
},
"ContributorActionJson": {
"description": "Ban the Author of the Activity this Check is run on",
"properties": {
"action": {
"$ref": "#/definitions/ContributorActionType"
},
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"contributor"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
}
},
"required": [
"action",
"kind"
],
"type": "object"
},
"ContributorActionType": {
"enum": [
"add",
"remove"
],
"type": "string"
},
"DatabaseStatisticsJsonConfig": {
"properties": {
"frequency": {
"description": "Specify the frequency for collecting time-series statistics.\n\nValid values are: 'minute','hour','day','week','month','year' OR false to disable collection",
"enum": [
"day",
false,
"hour",
"minute",
"month",
"week",
"year"
]
}
},
"type": "object"
},
"DiscordProviderConfig": {
"properties": {
"name": {
"type": "string"
},
"type": {
"enum": [
"discord"
],
"type": "string"
},
"url": {
"type": "string"
}
},
"required": [
"name",
"type",
"url"
],
"type": "object"
},
"DispatchActionJson": {
"description": "Remove the Activity",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"cancelIfQueued": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"items": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"enum": [
"poll",
"poll:modqueue",
"poll:newComm",
"poll:newSub",
"poll:unmoderated",
"user"
],
"type": "string"
}
]
},
"type": "array"
},
{
"enum": [
false,
"poll",
"poll:modqueue",
"poll:newComm",
"poll:newSub",
"poll:unmoderated",
true,
"user"
]
}
]
},
"delay": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"type": "string"
}
]
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"goto": {
"type": "string"
},
"identifier": {
"type": "string"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"dispatch"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"onExistingFound": {
"enum": [
"ignore",
"replace",
"skip"
],
"type": "string"
},
"tardyTolerant": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"type": [
"string",
"boolean"
]
}
]
},
"target": {
"anyOf": [
{
"items": {
"enum": [
"parent",
"self"
],
"type": "string"
},
"type": "array"
},
{
"enum": [
"parent",
"self"
],
"type": "string"
}
]
}
},
"required": [
"delay",
"kind",
"target"
],
"type": "object"
},
"DurationObject": {
"additionalProperties": false,
"description": "A [Day.js duration object](https://day.js.org/docs/en/durations/creating)",
"examples": [
{
"hours": 1,
"minutes": 30
}
],
"minProperties": 1,
"properties": {
"days": {
"examples": [
7
],
"type": "number"
},
"hours": {
"examples": [
4
],
"type": "number"
},
"minutes": {
"examples": [
50
],
"type": "number"
},
"months": {
"examples": [
3
],
"type": "number"
},
"seconds": {
"examples": [
15
],
"type": "number"
},
"weeks": {
"examples": [
2
],
"type": "number"
},
"years": {
"examples": [
0
],
"type": "number"
}
},
"type": "object"
},
"FilterCriteriaDefaultsJson": {
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "Determine how authorIs defaults behave when authorIs is present on the check\n\n* merge => merges defaults with check's authorIs\n* replace => check authorIs will replace defaults (no defaults used)"
},
"authorIsBehavior": {
"enum": [
"merge",
"replace"
],
"type": "string"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
]
},
"itemIsBehavior": {
"description": "Determine how itemIs defaults behave when itemIs is present on the check\n\n* merge => adds defaults to check's itemIs\n* replace => check itemIs will replace defaults (no defaults used)",
"enum": [
"merge",
"replace"
],
"type": "string"
}
},
"type": "object"
},
"FilterOptionsConfig<ActivityState>": {
"properties": {
"exclude": {
"description": "Only runs if `include` is not present. Each Criteria is comprised of conditions that the filter (Author/Item) being checked must \"not\" pass. See excludeCondition for set behavior\n\nEX: `isMod: true, name: Automoderator` => Will pass if the Author IS NOT a mod and IS NOT named Automoderator",
"items": {
"anyOf": [
{
"$ref": "#/definitions/ActivityState"
},
{
"$ref": "#/definitions/NamedCriteria<ActivityState>"
}
]
},
"type": "array"
},
"excludeCondition": {
"default": "OR",
"description": "* OR => if ANY exclude condition \"does not\" pass then the exclude test passes\n* AND => if ALL exclude conditions \"do not\" pass then the exclude test passes\n\nDefaults to OR",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"include": {
"description": "Will \"pass\" if any set of Criteria passes",
"items": {
"anyOf": [
{
"$ref": "#/definitions/ActivityState"
},
{
"$ref": "#/definitions/NamedCriteria<ActivityState>"
}
]
},
"type": "array"
}
},
"type": "object"
},
"FilterOptionsConfig<CommentState>": {
"properties": {
"exclude": {
"description": "Only runs if `include` is not present. Each Criteria is comprised of conditions that the filter (Author/Item) being checked must \"not\" pass. See excludeCondition for set behavior\n\nEX: `isMod: true, name: Automoderator` => Will pass if the Author IS NOT a mod and IS NOT named Automoderator",
"items": {
"anyOf": [
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<CommentState>"
}
]
},
"type": "array"
},
"excludeCondition": {
"default": "OR",
"description": "* OR => if ANY exclude condition \"does not\" pass then the exclude test passes\n* AND => if ALL exclude conditions \"do not\" pass then the exclude test passes\n\nDefaults to OR",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"include": {
"description": "Will \"pass\" if any set of Criteria passes",
"items": {
"anyOf": [
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<CommentState>"
}
]
},
"type": "array"
}
},
"type": "object"
},
"FilterOptionsConfig<SubmissionState>": {
"properties": {
"exclude": {
"description": "Only runs if `include` is not present. Each Criteria is comprised of conditions that the filter (Author/Item) being checked must \"not\" pass. See excludeCondition for set behavior\n\nEX: `isMod: true, name: Automoderator` => Will pass if the Author IS NOT a mod and IS NOT named Automoderator",
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/NamedCriteria<SubmissionState>"
}
]
},
"type": "array"
},
"excludeCondition": {
"default": "OR",
"description": "* OR => if ANY exclude condition \"does not\" pass then the exclude test passes\n* AND => if ALL exclude conditions \"do not\" pass then the exclude test passes\n\nDefaults to OR",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"include": {
"description": "Will \"pass\" if any set of Criteria passes",
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/NamedCriteria<SubmissionState>"
}
]
},
"type": "array"
}
},
"type": "object"
},
"FilterOptionsJson<AuthorCriteria>": {
"properties": {
"exclude": {
"description": "Only runs if `include` is not present. Each Criteria is comprised of conditions that the filter (Author/Item) being checked must \"not\" pass. See excludeCondition for set behavior\n\nEX: `isMod: true, name: Automoderator` => Will pass if the Author IS NOT a mod and IS NOT named Automoderator",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
"excludeCondition": {
"default": "OR",
"description": "* OR => if ANY exclude condition \"does not\" pass then the exclude test passes\n* AND => if ALL exclude conditions \"do not\" pass then the exclude test passes\n\nDefaults to OR",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"include": {
"description": "Will \"pass\" if any set of Criteria passes",
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
}
},
"type": "object"
},
"FilterOptionsJson<SubredditCriteria>": {
"properties": {
"exclude": {
"description": "Only runs if `include` is not present. Each Criteria is comprised of conditions that the filter (Author/Item) being checked must \"not\" pass. See excludeCondition for set behavior\n\nEX: `isMod: true, name: Automoderator` => Will pass if the Author IS NOT a mod and IS NOT named Automoderator",
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubredditCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<SubredditCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
"excludeCondition": {
"default": "OR",
"description": "* OR => if ANY exclude condition \"does not\" pass then the exclude test passes\n* AND => if ALL exclude conditions \"do not\" pass then the exclude test passes\n\nDefaults to OR",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"include": {
"description": "Will \"pass\" if any set of Criteria passes",
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubredditCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<SubredditCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
}
},
"type": "object"
},
"FilterOptionsJson<TypedActivityState>": {
"properties": {
"exclude": {
"description": "Only runs if `include` is not present. Each Criteria is comprised of conditions that the filter (Author/Item) being checked must \"not\" pass. See excludeCondition for set behavior\n\nEX: `isMod: true, name: Automoderator` => Will pass if the Author IS NOT a mod and IS NOT named Automoderator",
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
"excludeCondition": {
"default": "OR",
"description": "* OR => if ANY exclude condition \"does not\" pass then the exclude test passes\n* AND => if ALL exclude conditions \"do not\" pass then the exclude test passes\n\nDefaults to OR",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"include": {
"description": "Will \"pass\" if any set of Criteria passes",
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
}
},
"type": "object"
},
"FlairActionJson": {
"description": "Flair the Submission",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"css": {
"description": "The text of the css class of the flair to apply",
"type": "string"
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"flair_template_id": {
"description": "Flair template ID to assign",
"type": "string"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"flair"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"text": {
"description": "The text of the flair to apply",
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"FullActivityWindowConfig": {
"additionalProperties": false,
"description": "Multiple properties that may be used to define what range of Activity to retrieve.\n\nMay specify one, or both properties along with the `satisfyOn` property, to affect the retrieval behavior.",
"examples": [
{
"count": 100,
"duration": {
"days": 90
}
}
],
"minProperties": 1,
"properties": {
"activityState": {
"$ref": "#/definitions/FilterOptionsConfig<ActivityState>",
"description": "When present, will only return Activities (Comment or Submission) retrieved from history that pass this filter"
},
"chunkSize": {
"description": "The number of Activities to retrieve on each API call. Defaults to 100 (maximum allowed).\n\nThere is no reason to change this unless you are highly bandwidth-constrained and have a known problem space. Overridden by `count` when `count` <= 100",
"type": "number"
},
"commentState": {
"$ref": "#/definitions/FilterOptionsConfig<CommentState>",
"description": "When present, will only return Comments retrieved from history that pass this filter\n\nTakes precedence over `activityState`"
},
"count": {
"description": "The number of activities (submission/comments) to consider",
"examples": [
15
],
"type": "number"
},
"debug": {
"description": "Output additional information and all filter output to debug log",
"type": "boolean"
},
"duration": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"type": "string"
}
],
"description": "A value that specifies the amount of time to subtract from `NOW` to create a time range IE `NOW <---> [duration] ago`\n\nAcceptable values:\n\n**A `string` consisting of a value and a [Day.js](https://day.js.org/docs/en/durations/creating) time unit** ([test your value](https://regexr.com/61em3))\n\n* EX `9 days` => Range is `NOW <---> 9 days ago`\n\n**A [Day.js](https://day.js.org/docs/en/durations/creating) `object`**\n\n* EX `{\"days\": 90, \"minutes\": 15}` => Range is `NOW <---> 90 days and 15 minutes ago`\n\n**An [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) `string`** ([test your value](https://regexr.com/61em9))\n\n* EX `PT15M` => 15 minutes => Range is `NOW <----> 15 minutes ago`",
"examples": [
"90 days",
"PT15M",
{
"minutes": 15
}
]
},
"fetch": {
"description": "Specify the type of Activity (Comment or Submission) to retrieve for the window.\n\nWill be overridden if the type is specified in a parent rule (with property such as 'lookAs')",
"enum": [
"all",
"comment",
"comments",
"overview",
"submission",
"submissions"
],
"type": "string"
},
"filterOn": {
"description": "Use to filter the Activities retrieved by subreddit or activity state\n\nCan be filtered **during** fetching using `pre` or **after** fetching results using `post`",
"properties": {
"post": {
"$ref": "#/definitions/HistoryFiltersConfig",
"description": "Filters to run AFTER `count` and `duration` conditions have been triggered. Will filter the entire set of returned Activities."
},
"pre": {
"$ref": "#/definitions/PreHistoryFiltersConfig",
"description": "Filters to run for each new chunk of Activities retrieved. `count` and `duration` conditions will be checked AFTER filtering the new chunk"
}
},
"type": "object"
},
"satisfyOn": {
"default": "any",
"description": "Define the condition under which both criteria are considered met\n\n**If `any` then it will retrieve Activities until one of the criteria is met, whichever occurs first**\n\nEX `{\"count\": 100, duration: \"90 days\"}`:\n* If 90 days of activities = 40 activities => returns 40 activities\n* If 100 activities is only 20 days => 100 activities\n\n**If `all` then both criteria must be met.**\n\nEffectively, whichever criteria produces the most Activities...\n\nEX `{\"count\": 100, duration: \"90 days\"}`:\n* If at 90 days of activities => 40 activities, continue retrieving results until 100 => results in >90 days of activities\n* If at 100 activities => 20 days of activities, continue retrieving results until 90 days => results in >100 activities",
"enum": [
"all",
"any"
],
"examples": [
"any"
],
"type": "string"
},
"sort": {
"enum": [
"controversial",
"hot",
"new",
"top"
],
"type": "string"
},
"sortTime": {
"enum": [
"all",
"day",
"hour",
"month",
"week",
"year"
],
"type": "string"
},
"submissionState": {
"$ref": "#/definitions/FilterOptionsConfig<SubmissionState>",
"description": "When present, will only return Submissions retrieved from history that pass this filter\n\nTakes precedence over `activityState`"
},
"subreddits": {
"$ref": "#/definitions/FilterOptionsJson<SubredditCriteria>",
"description": "Filter Activities based on their Subreddit."
}
},
"type": "object"
},
"HistoricalMHSConfig": {
"description": "Test the content of Activities from the Author history against MHS criteria\n\nIf this is defined then the `totalMatching` threshold must pass for the Rule to trigger\n\nIf `criteria` is defined here it overrides the top-level `criteria` value",
"properties": {
"criteria": {
"$ref": "#/definitions/MHSCriteriaConfig",
"description": "Criteria used to trigger based on MHS results\n\nIf both `flagged` and `confidence` are specified then both conditions must pass.\n\nBy default, only `flagged` is defined as `true`"
},
"mustMatchCurrent": {
"default": false,
"description": "When `true` the original Activity being checked MUST pass its criteria before the Rule considers any history",
"type": "boolean"
},
"totalMatching": {
"default": "> 0",
"description": "A string containing a comparison operator and a value to compare Activities from history that pass the given `criteria` test\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign]`\n\n* EX `> 12` => greater than 12 activities passed given `criteria` test\n* EX `<= 10%` => less than 10% of all Activities from history passed given `criteria` test",
"examples": [
"> 0",
"> 10%"
],
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"window": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"$ref": "#/definitions/FullActivityWindowConfig"
},
{
"type": [
"string",
"number"
]
}
],
"description": "A value to define the range of Activities to retrieve.\n\nAcceptable values:\n\n**`ActivityWindowCriteria` object**\n\nAllows specify multiple range properties and more specific behavior\n\n**A `number` of Activities to retrieve**\n\n* EX `100` => 100 Activities\n\n*****\n\nAny of the below values that specify the amount of time to subtract from `NOW` to create a time range IE `NOW <---> [duration] ago`\n\nAcceptable values:\n\n**A `string` consisting of a value and a [Day.js](https://day.js.org/docs/en/durations/creating#list-of-all-available-units) time UNIT**\n\n* EX `9 days` => Range is `NOW <---> 9 days ago`\n\n**A [Day.js](https://day.js.org/docs/en/durations/creating) `object`**\n\n* EX `{\"days\": 90, \"minutes\": 15}` => Range is `NOW <---> 90 days and 15 minutes ago`\n\n**An [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) `string`**\n\n* EX `PT15M` => 15 minutes => Range is `NOW <----> 15 minutes ago`",
"examples": [
"90 days"
]
}
},
"required": [
"totalMatching",
"window"
],
"type": "object"
},
"HistoricalSentimentConfig": {
"description": "Test the Sentiment of Activities from the Author history\n\nIf this is defined then the `totalMatching` threshold must pass for the Rule to trigger\n\nIf `sentiment` is defined here it overrides the top-level `sentiment` value",
"properties": {
"mustMatchCurrent": {
"default": false,
"description": "When `true` the original Activity being checked MUST match desired sentiment before the Rule considers any history",
"type": "boolean"
},
"sentiment": {
"description": "Test the calculated VADER sentiment (compound) score for an Activity using this comparison. Can be either a numerical or natural language\n\nSentiment values range from extremely negative to extremely positive in a numerical range of -1 to +1:\n\n* -0.6 => extremely negative\n* -0.3 => very negative\n* -0.1 => negative\n* 0 => neutral\n* 0.1 => positive\n* 0.3 => very positive\n* 0.6 => extremely positive\n\nThe below examples are all equivocal. You can use either set of values as the value for `sentiment` (numerical comparisons or natural langauge)\n\n* `>= 0.1` = `is positive`\n* `<= 0.3` = `is very negative`\n* `< 0.1` = `is not positive`\n* `> -0.3` = `is not very negative`\n\nSpecial case:\n\n* `is neutral` equates to `> -0.1 and < 0.1`\n* `is not neutral` equates to `< -0.1 or > 0.1`\n\nContextMod uses a normalized, weighted average from these sentiment tools:\n\n* NLP.js (english, french, german, and spanish) https://github.com/axa-group/nlp.js/blob/master/docs/v3/sentiment-analysis.md\n* (english only) vaderSentiment-js https://github.com/vaderSentiment/vaderSentiment-js/\n* (english only) wink-sentiment https://github.com/winkjs/wink-sentiment\n\nMore about the sentiment algorithms used:\n* VADER https://github.com/cjhutto/vaderSentiment\n* AFINN http://corpustext.com/reference/sentiment_afinn.html\n* Senticon https://ieeexplore.ieee.org/document/8721408\n* Pattern https://github.com/clips/pattern\n* wink https://github.com/winkjs/wink-sentiment",
"examples": [
"is negative",
"> 0.2"
],
"pattern": "((>|>=|<|<=)\\s*(-?\\d?\\.?\\d+))|((not)?\\s*(very|extremely)?\\s*(positive|neutral|negative))",
"type": "string"
},
"totalMatching": {
"default": "> 0",
"description": "A string containing a comparison operator and a value to compare Activities from history that pass the given `sentiment` comparison\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign]`\n\n* EX `> 12` => greater than 12 activities passed given `sentiment` comparison\n* EX `<= 10%` => less than 10% of all Activities from history passed given `sentiment` comparison",
"examples": [
"> 0",
"> 10%"
],
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"window": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"$ref": "#/definitions/FullActivityWindowConfig"
},
{
"type": [
"string",
"number"
]
}
],
"description": "A value to define the range of Activities to retrieve.\n\nAcceptable values:\n\n**`ActivityWindowCriteria` object**\n\nAllows specify multiple range properties and more specific behavior\n\n**A `number` of Activities to retrieve**\n\n* EX `100` => 100 Activities\n\n*****\n\nAny of the below values that specify the amount of time to subtract from `NOW` to create a time range IE `NOW <---> [duration] ago`\n\nAcceptable values:\n\n**A `string` consisting of a value and a [Day.js](https://day.js.org/docs/en/durations/creating#list-of-all-available-units) time UNIT**\n\n* EX `9 days` => Range is `NOW <---> 9 days ago`\n\n**A [Day.js](https://day.js.org/docs/en/durations/creating) `object`**\n\n* EX `{\"days\": 90, \"minutes\": 15}` => Range is `NOW <---> 90 days and 15 minutes ago`\n\n**An [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) `string`**\n\n* EX `PT15M` => 15 minutes => Range is `NOW <----> 15 minutes ago`",
"examples": [
"90 days"
]
}
},
"required": [
"totalMatching",
"window"
],
"type": "object"
},
"HistoryCriteria": {
"description": "Criteria will only trigger if ALL present thresholds (comment, submission, total) are met",
"properties": {
"comment": {
"description": "A string containing a comparison operator and a value to compare **filtered** (using `include` or `exclude`, if present) comments against\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign] [OP]`\n\n* EX `> 100` => greater than 100 comments\n* EX `<= 75%` => comments are equal to or less than 75% of unfiltered Activities\n\nIf your string also contains the text `OP` somewhere **after** `<number>[percent sign]`...:\n\n* EX `> 100 OP` => greater than 100 filtered comments as OP\n* EX `<= 25% as OP` => **Filtered** comments as OP were less then or equal to 25% of **unfiltered Comments**",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"minActivityCount": {
"default": 5,
"description": "The minimum number of **filtered** activities that must exist from the `window` results for this criteria to run",
"type": "number"
},
"name": {
"type": "string"
},
"ratio": {
"properties": {
"threshold": {
"description": "A string containing a comparison operator and a value to compare number of parent criteria activities against number of \"ratio\" activities\n\nThis comparison is always done as (number of parent criteria activities) / (number of ratio activities)\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign]`\n\n* EX `> 1.2` => There are 1.2 activities from parent criteria for every 1 ratio activities\n* EX `<= 75%` => There are equal to or less than 0.75 activities from parent criteria for every 1 ratio activities",
"pattern": "^\\s*(>|>=|<|<=)\\s*((?:\\d+)(?:(?:(?:.|,)\\d+)+)?)\\s*(%?)(.*)$",
"type": "string"
},
"window": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"$ref": "#/definitions/FullActivityWindowConfig"
},
{
"type": [
"string",
"number"
]
}
],
"description": "A value to define the range of Activities to retrieve.\n\nAcceptable values:\n\n**`ActivityWindowCriteria` object**\n\nAllows specify multiple range properties and more specific behavior\n\n**A `number` of Activities to retrieve**\n\n* EX `100` => 100 Activities\n\n*****\n\nAny of the below values that specify the amount of time to subtract from `NOW` to create a time range IE `NOW <---> [duration] ago`\n\nAcceptable values:\n\n**A `string` consisting of a value and a [Day.js](https://day.js.org/docs/en/durations/creating#list-of-all-available-units) time UNIT**\n\n* EX `9 days` => Range is `NOW <---> 9 days ago`\n\n**A [Day.js](https://day.js.org/docs/en/durations/creating) `object`**\n\n* EX `{\"days\": 90, \"minutes\": 15}` => Range is `NOW <---> 90 days and 15 minutes ago`\n\n**An [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) `string`**\n\n* EX `PT15M` => 15 minutes => Range is `NOW <----> 15 minutes ago`",
"examples": [
"90 days"
]
}
},
"required": [
"threshold",
"window"
],
"type": "object"
},
"submission": {
"description": "A string containing a comparison operator and a value to compare **filtered** (using `include` or `exclude`, if present) submissions against\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign]`\n\n* EX `> 100` => greater than 100 filtered submissions\n* EX `<= 75%` => filtered submissions are equal to or less than 75% of unfiltered Activities",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"total": {
"description": "A string containing a comparison operator and a value to compare **filtered** (using `include` or `exclude`) activities against\n\n**Note:** This is only useful if using `include` or `exclude` otherwise percent will always be 100% and total === activityTotal\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign] [OP]`\n\n* EX `> 100` => greater than 100 filtered activities\n* EX `<= 75%` => filtered activities are equal to or less than 75% of all Activities",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"window": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"$ref": "#/definitions/FullActivityWindowConfig"
},
{
"type": [
"string",
"number"
]
}
],
"description": "A value to define the range of Activities to retrieve.\n\nAcceptable values:\n\n**`ActivityWindowCriteria` object**\n\nAllows specify multiple range properties and more specific behavior\n\n**A `number` of Activities to retrieve**\n\n* EX `100` => 100 Activities\n\n*****\n\nAny of the below values that specify the amount of time to subtract from `NOW` to create a time range IE `NOW <---> [duration] ago`\n\nAcceptable values:\n\n**A `string` consisting of a value and a [Day.js](https://day.js.org/docs/en/durations/creating#list-of-all-available-units) time UNIT**\n\n* EX `9 days` => Range is `NOW <---> 9 days ago`\n\n**A [Day.js](https://day.js.org/docs/en/durations/creating) `object`**\n\n* EX `{\"days\": 90, \"minutes\": 15}` => Range is `NOW <---> 90 days and 15 minutes ago`\n\n**An [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) `string`**\n\n* EX `PT15M` => 15 minutes => Range is `NOW <----> 15 minutes ago`",
"examples": [
"90 days"
]
}
},
"required": [
"window"
],
"type": "object"
},
"HistoryFiltersConfig": {
"properties": {
"activityState": {
"$ref": "#/definitions/FilterOptionsConfig<ActivityState>",
"description": "When present, will only return Activities (Comment or Submission) retrieved from history that pass this filter"
},
"commentState": {
"$ref": "#/definitions/FilterOptionsConfig<CommentState>",
"description": "When present, will only return Comments retrieved from history that pass this filter\n\nTakes precedence over `activityState`"
},
"debug": {
"description": "Output individual filter results for each Activity tested to debug\n\nIf present overrides `debug` set at window level.",
"type": "boolean"
},
"submissionState": {
"$ref": "#/definitions/FilterOptionsConfig<SubmissionState>",
"description": "When present, will only return Submissions retrieved from history that pass this filter\n\nTakes precedence over `activityState`"
},
"subreddits": {
"$ref": "#/definitions/FilterOptionsJson<SubredditCriteria>",
"description": "Filter Activities based on their Subreddit."
}
},
"type": "object"
},
"HistoryJSONConfig": {
"description": "Aggregates an Author's submission and comment history. Rule can be triggered on count/percent of total (for either or both comment/sub totals) as well as comment OP total.\n\nAvailable data for [Action templating](https://github.com/FoxxMD/context-mod#action-templating):\n\n```\nactivityTotal => Total number of activities\nsubmissionTotal => Total number of submissions\ncommentTotal => Total number of comments\nopTotal => Total number of comments as OP\nthresholdSummary => A text summary of the first Criteria triggered with totals/percentages\ncriteria => The ThresholdCriteria object\nwindow => A text summary of the range of Activities considered (# of Items if number, time range if Duration)\n```",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"condition": {
"description": "* If `OR` then any set of Criteria that pass will trigger the Rule\n* If `AND` then all Criteria sets must pass to trigger the Rule",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"criteria": {
"description": "A list threshold-window values to test activities against.",
"items": {
"$ref": "#/definitions/HistoryCriteria"
},
"minItems": 1,
"type": "array"
},
"exclude": {
"description": "If present, activities will be counted only if they are **NOT** found in this list of Subreddits\n\nEach value in the list can be either:\n\n * string (name of subreddit)\n * regular expression to run on the subreddit name\n * `SubredditState`\n\nEX `[\"mealtimevideos\",\"askscience\", \"/onlyfans*\\/i\", {\"over18\": true}]`\n\n**Note:** This affects **post-window retrieval** activities. So that:\n\n* `activityTotal` is number of activities retrieved from `window` -- NOT post-filtering\n* all comparisons using **percentages** will compare **post-filtering** results against **activity count from window**\n* -- to run this rule where all activities are only from include/exclude filtering instead use include/exclude in `window`",
"examples": [
[
"mealtimevideos",
"askscience",
"/onlyfans*/i",
{
"over18": true
}
]
],
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubredditCriteria"
},
{
"type": "string"
}
]
},
"type": "array"
},
"include": {
"description": "If present, activities will be counted only if they are found in this list of Subreddits.\n\nEach value in the list can be either:\n\n * string (name of subreddit)\n * regular expression to run on the subreddit name\n * `SubredditState`\n\nEX `[\"mealtimevideos\",\"askscience\", \"/onlyfans*\\/i\", {\"over18\": true}]`\n\n **Note:** This affects **post-window retrieval** activities. So that:\n\n* `activityTotal` is number of activities retrieved from `window` -- NOT post-filtering\n* all comparisons using **percentages** will compare **post-filtering** results against **activity count from window**\n* -- to run this rule where all activities are only from include/exclude filtering instead use include/exclude in `window`",
"examples": [
[
"mealtimevideos",
"askscience",
"/onlyfans*/i",
{
"over18": true
}
]
],
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubredditCriteria"
},
{
"type": "string"
}
]
},
"type": "array"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The kind of rule to run",
"enum": [
"history"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this rule. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes\n\nname is used to reference Rule result data during Action content templating. See CommentAction or ReportAction for more details.",
"examples": [
"myNewRule"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
}
},
"required": [
"criteria",
"kind"
],
"type": "object"
},
"ImageDetection": {
"description": "When comparing submissions detect if the reference submission is an image and do a pixel-comparison to other detected image submissions.\n\n**Note:** This is an **experimental feature**",
"properties": {
"enable": {
"description": "Is image detection enabled?",
"type": "boolean"
},
"fetchBehavior": {
"default": "extension",
"description": "Determines how and when to check if a URL is an image\n\n**Note:** After fetching a URL the **Content-Type** is validated to contain `image` before detection occurs\n\n**When `extension`:** (default)\n\n* Only URLs that end in known image extensions (.png, .jpg, etc...) are fetched\n\n**When `unknown`:**\n\n* URLs that end in known image extensions (.png, .jpg, etc...) are fetched\n* URLs with no extension or unknown (IE non-video, non-doc, etc...) are fetched\n\n**When `all`:**\n\n* All submissions that have URLs (non-self) will be fetched, regardless of extension\n* **Note:** This can be bandwidth/CPU intensive if history window is large so use with care",
"enum": [
"all",
"extension",
"unknown"
],
"type": "string"
},
"hash": {
"description": "Use perceptual hashing (blockhash-js) to compare images\n\nPros:\n\n* very fast\n* low cpu/memory usage\n* results can be cached\n\nCons:\n\n* not as accurate as pixel comparison\n* weaker for text-heavy images\n* mostly color-blind\n\nBest uses:\n\n* Detecting (general) duplicate images\n* Comparing large number of images",
"properties": {
"bits": {
"default": 32,
"description": "Bit count determines accuracy of hash and granularity of hash comparison (comparison to other hashes)\n\nDefault is `32`\n\n**NOTE:** Hashes of different sizes (bits) cannot be compared. If you are caching results make sure all rules where results may be shared use the same bit count to ensure hashes can be compared. Otherwise hashes will be recomputed.",
"type": "number"
},
"enable": {
"default": true,
"description": "Enabled by default.\n\nIf both `hash` and `pixel` are enabled then `pixel` will be used to verify image comparison when hashes matches",
"type": "boolean"
},
"hardThreshold": {
"description": "High Confidence Threshold\n\nIf the difference in comparison is equal to or less than this number the images are considered the same and pixel comparison WILL NOT occur\n\nDefaults to the parent-level `threshold` value if not present\n\nUse `null` if you want pixel comparison to ALWAYS occur (softThreshold must be present)",
"type": [
"null",
"number"
]
},
"softThreshold": {
"description": "Low Confidence Threshold -- only used if `pixel` is enabled\n\nIf the difference in comparison is\n\n1) equal to or less than this value and\n2) the value is greater than `hardThreshold`\n\nthe images will be compared using the `pixel` method",
"type": "number"
},
"ttl": {
"description": "Number of seconds to cache image hash",
"type": "number"
}
},
"type": "object"
},
"pixel": {
"description": "Use pixel counting to compare images\n\nPros:\n\n* most accurate\n* strong with text or color-only changes\n\nCons:\n\n* much slower than hashing\n* memory/cpu intensive\n\nBest uses:\n\n* Comparison text-only images\n* Comparison requires high degree of accuracy or changes are subtle",
"properties": {
"enable": {
"default": false,
"description": "Disabled by default.",
"type": "boolean"
},
"threshold": {
"description": "The percentage, as a whole number, of pixels that are **different** between the two images at which point the images are not considered the same.",
"type": "number"
}
},
"type": "object"
},
"threshold": {
"default": 5,
"description": "The percentage, as a whole number, of difference between two images at which point they will not be considered the same.\n\nWill be used as `hash.hardThreshold` and `pixel.threshold` if those values are not specified\n\nDefault is `5`",
"type": "number"
}
},
"type": "object"
},
"IncludesData": {
"properties": {
"path": {
"description": "The special-form path to the config fragment to retrieve.\n\nIf value starts with `wiki:` then the proceeding value will be used to get a wiki page from the current subreddit\n\n * EX `wiki:botconfig/mybot` tries to get `https://reddit.com/r/currentSubreddit/wiki/botconfig/mybot`\n\nIf the value starts with `wiki:` and ends with `|someValue` then `someValue` will be used as the base subreddit for the wiki page\n\n* EX `wiki:replytemplates/test|ContextModBot` tries to get `https://reddit.com/r/ContextModBot/wiki/replytemplates/test`\n\nIf the value starts with `url:` then the value is fetched as an external url and expects raw text returned\n\n* EX `url:https://pastebin.com/raw/38qfL7mL` tries to get the text response of `https://pastebin.com/raw/38qfL7mL`",
"type": "string"
},
"ttl": {
"anyOf": [
{
"enum": [
false,
"response",
true
]
},
{
"type": "number"
}
],
"description": "Control caching for the config fragment.\n\nIf not specified the value for `wikiTTL` will be used\n\n* If true then value is cached forever\n* If false then value is never cached\n* If a number then the number of seconds to cache value\n* If 'response' then CM will attempt to use Cache-Control or Expires headers from the response to determine how long to cache the value"
},
"type": {
"description": "An unused hint about the content type. Not implemented yet",
"enum": [
"json",
"yaml"
],
"type": "string"
}
},
"required": [
"path"
],
"type": "object"
},
"LockActionJson": {
"description": "Lock the Activity",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"lock"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"MHSCriteriaConfig": {
"description": "Criteria used to trigger based on MHS results\n\nIf both `flagged` and `confidence` are specified then both conditions must pass.\n\nBy default, only `flagged` is defined as `true`",
"properties": {
"confidence": {
"description": "A string containing a comparison operator and a value to compare against the confidence returned from MHS\n\nThe syntax is `(< OR > OR <= OR >=) <number>`\n\n* EX `> 50` => MHS confidence is greater than 50%",
"examples": [
"> 50"
],
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"flagged": {
"default": true,
"description": "Test if MHS considers content flagged as toxic or not",
"type": "boolean"
},
"testOn": {
"default": [
"body"
],
"description": "Which content from an Activity to send to MHS\n\nOnly used if the Activity being tested is a Submission -- Comments can be only tested against their body\n\nIf more than one type of content is specified then all text is tested together as one string",
"items": {
"enum": [
"body",
"title"
],
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"MHSRuleJSONConfig": {
"description": "Test content of an Activity against the MHS toxicity model for reddit content\n\nRunning this Rule with no configuration will use a default configuration that will cause the Rule to trigger if MHS flags the content of the Activity as toxic.\n\nMore info:\n\n* https://moderatehatespeech.com/docs/\n* https://moderatehatespeech.com/",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"criteria": {
"$ref": "#/definitions/MHSCriteriaConfig",
"description": "Criteria used to trigger based on MHS results\n\nIf both `flagged` and `confidence` are specified then both conditions must pass.\n\nBy default, only `flagged` is defined as `true`"
},
"historical": {
"$ref": "#/definitions/HistoricalMHSConfig",
"description": "run MHS on Activities from the Author history\n\nIf this is defined then the `totalMatching` threshold must pass for the Rule to trigger\n\nIf `criteria` is defined here it overrides the top-level `criteria` value"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"default": "mhs",
"description": "The kind of rule to run",
"enum": [
"mhs"
],
"examples": [
"mhs"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this rule. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes\n\nname is used to reference Rule result data during Action content templating. See CommentAction or ReportAction for more details.",
"examples": [
"myNewRule"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"MessageActionJson": {
"description": "Send a private message to the Author of the Activity.",
"properties": {
"asSubreddit": {
"description": "Should this message be sent from modmail (as the subreddit) or as the bot user?",
"type": "boolean"
},
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"content": {
"description": "The Content to submit for this Action. Content is interpreted as reddit-flavored Markdown.\n\nIf value starts with `wiki:` then the proceeding value will be used to get a wiki page from the current subreddit\n\n * EX `wiki:botconfig/mybot` tries to get `https://reddit.com/r/currentSubreddit/wiki/botconfig/mybot`\n\nIf the value starts with `wiki:` and ends with `|someValue` then `someValue` will be used as the base subreddit for the wiki page\n\n* EX `wiki:replytemplates/test|ContextModBot` tries to get `https://reddit.com/r/ContextModBot/wiki/replytemplates/test`\n\nIf the value starts with `url:` then the value is fetched as an external url and expects raw text returned\n\n* EX `url:https://pastebin.com/raw/38qfL7mL` tries to get the text response of `https://pastebin.com/raw/38qfL7mL`\n\nIf none of the above is used the value is treated as the raw context\n\n * EX `this is **bold** markdown text` => \"this is **bold** markdown text\"\n\nAll Content is rendered using [mustache](https://github.com/janl/mustache.js/#templates) to enable [Action Templating](https://github.com/FoxxMD/context-mod#action-templating).\n\nThe following properties are always available in the template (view individual Rules to see rule-specific template data):\n```\nitem.kind => The type of Activity that was checked (comment/submission)\nitem.author => The name of the Author of the Activity EX FoxxMD\nitem.permalink => A permalink URL to the Activity EX https://reddit.com/r/yourSub/comments/o1h0i0/title_name/1v3b7x\nitem.url => If the Activity is Link Sumbission then the external URL\nitem.title => If the Activity is a Submission then the title of that Submission\nrules => An object containing RuleResults of all the rules run for this check. See Action Templating for more details on naming\n```",
"type": "string"
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"footer": {
"anyOf": [
{
"enum": [
false
],
"type": "boolean"
},
{
"type": "string"
}
],
"description": "Customize the footer for Actions that send replies (Comment/Ban)\n\nIf `false` no footer is appended\n\nIf `string` the value is rendered as markdown or will use `wiki:` parser the same way `content` properties on Actions are rendered with [templating](https://github.com/FoxxMD/context-mod#action-templating).\n\nIf footer is `undefined` (not set) the default footer will be used:\n\n> *****\n> This action was performed by [a bot.] Mention a moderator or [send a modmail] if you any ideas, questions, or concerns about this action.\n\n*****\n\nThe following properties are available for [templating](https://github.com/FoxxMD/context-mod#action-templating):\n```\nsubName => name of subreddit Action was performed in (EX 'mealtimevideos')\npermaLink => The permalink for the Activity the Action was performed on EX https://reddit.com/r/yourSub/comments/o1h0i0/title_name/1v3b7x\nmodmaiLink => An encoded URL that will open a new message to your subreddit with the Action permalink appended to the body\nbotLink => A permalink to the FAQ for this bot.\n```\nIf you use your own footer or no footer **please link back to the bot FAQ** using the `{{botLink}}` property in your content :)"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"message"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"title": {
"description": "The title of the message\n\nIf not specified will be defaulted to `Concerning your [Submission/Comment]`",
"type": "string"
},
"to": {
"description": "Entity to send message to. It can be templated.\n\nIf not present Message be will sent to the Author of the Activity being checked.\n\nValid formats:\n\n* `aUserName` -- send to /u/aUserName\n* `u/aUserName` -- send to /u/aUserName\n* `r/aSubreddit` -- sent to modmail of /r/aSubreddit\n\n**Note:** Reddit does not support sending a message AS a subreddit TO another subreddit\n\n**Tip:** To send a message to the subreddit of the Activity us `to: 'r/{{item.subreddit}}'`",
"examples": [
"aUserName",
"u/aUserName",
"r/aSubreddit",
"r/{{item.subreddit}}"
],
"type": "string"
}
},
"required": [
"asSubreddit",
"content",
"kind"
],
"type": "object"
},
"ModLogCriteria": {
"properties": {
"action": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"activityType": {
"anyOf": [
{
"items": {
"enum": [
"comment",
false,
"submission"
]
},
"type": "array"
},
{
"enum": [
"comment",
false,
"submission"
]
}
]
},
"count": {
"default": ">= 1",
"description": "Number of occurrences of this type. Ignored if `search` is `current`\n\nA string containing a comparison operator and/or a value to compare number of occurrences against\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign] [in timeRange] [ascending|descending]`\n\nIf `timeRange` is given then only notes/mod actions that occur between timeRange and NOW will be returned. `timeRange` is ignored if search is `current`",
"examples": [
">= 1"
],
"pattern": "^\\s*(?<opStr>>|>=|<|<=)\\s*(?<value>\\d+)\\s*(?<percent>%?)\\s*(?<duration>in\\s+\\d+\\s*(days?|weeks?|months?|years?|hours?|minutes?|seconds?|milliseconds?))?\\s*(?<extra>asc.*|desc.*)*$",
"type": "string"
},
"description": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"details": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"referencesCurrentActivity": {
"type": "boolean"
},
"search": {
"default": "current",
"description": "How to test the Toolbox Notes or Mod Actions for this Author:\n\n### current\n\nOnly the most recent note is checked for criteria\n\n### total\n\n`count` comparison of mod actions/notes must be found within all history\n\n* EX `count: > 3` => Must have more than 3 notes of `type`, total\n* EX `count: <= 25%` => Must have 25% or less of notes of `type`, total\n* EX: `count: > 3 in 1 week` => Must have more than 3 notes within the last week\n\n### consecutive\n\nThe `count` **number** of mod actions/notes must be found in a row.\n\nYou may also specify the time-based order in which to search the notes by specifying `ascending (asc)` or `descending (desc)` in the `count` value. Default is `descending`\n\n* EX `count: >= 3` => Must have 3 or more notes of `type` consecutively, in descending order\n* EX `count: < 2` => Must have less than 2 notes of `type` consecutively, in descending order\n* EX `count: > 4 asc` => Must have greater than 4 notes of `type` consecutively, in ascending order",
"enum": [
"consecutive",
"current",
"total"
],
"examples": [
"current"
],
"type": "string"
},
"type": {
"anyOf": [
{
"items": {
"enum": [
"APPROVAL",
"INVITE",
"NOTE",
"REMOVAL",
"SPAM"
],
"type": "string"
},
"type": "array"
},
{
"enum": [
"APPROVAL",
"INVITE",
"NOTE",
"REMOVAL",
"SPAM"
],
"type": "string"
}
]
}
},
"type": "object"
},
"ModNoteActionJson": {
"description": "Add a Toolbox User Note to the Author of this Activity",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"content": {
"description": "The Content to submit for this Action. Content is interpreted as reddit-flavored Markdown.\n\nIf value starts with `wiki:` then the proceeding value will be used to get a wiki page from the current subreddit\n\n * EX `wiki:botconfig/mybot` tries to get `https://reddit.com/r/currentSubreddit/wiki/botconfig/mybot`\n\nIf the value starts with `wiki:` and ends with `|someValue` then `someValue` will be used as the base subreddit for the wiki page\n\n* EX `wiki:replytemplates/test|ContextModBot` tries to get `https://reddit.com/r/ContextModBot/wiki/replytemplates/test`\n\nIf the value starts with `url:` then the value is fetched as an external url and expects raw text returned\n\n* EX `url:https://pastebin.com/raw/38qfL7mL` tries to get the text response of `https://pastebin.com/raw/38qfL7mL`\n\nIf none of the above is used the value is treated as the raw context\n\n * EX `this is **bold** markdown text` => \"this is **bold** markdown text\"\n\nAll Content is rendered using [mustache](https://github.com/janl/mustache.js/#templates) to enable [Action Templating](https://github.com/FoxxMD/context-mod#action-templating).\n\nThe following properties are always available in the template (view individual Rules to see rule-specific template data):\n```\nitem.kind => The type of Activity that was checked (comment/submission)\nitem.author => The name of the Author of the Activity EX FoxxMD\nitem.permalink => A permalink URL to the Activity EX https://reddit.com/r/yourSub/comments/o1h0i0/title_name/1v3b7x\nitem.url => If the Activity is Link Sumbission then the external URL\nitem.title => If the Activity is a Submission then the title of that Submission\nrules => An object containing RuleResults of all the rules run for this check. See Action Templating for more details on naming\n```",
"examples": [
"This is the content of a comment/report/usernote",
"this is **bold** markdown text",
"wiki:botconfig/acomment"
],
"type": "string"
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"existingNoteCheck": {
"anyOf": [
{
"$ref": "#/definitions/ModNoteCriteria"
},
{
"type": "boolean"
}
],
"default": true,
"description": "Check if there is an existing Note matching some criteria before adding the Note.\n\nIf this check passes then the Note is added. The value may be a boolean or ModNoteCriteria.\n\nBoolean convenience:\n\n* If `true` or undefined then CM generates a ModNoteCriteria that passes only if there is NO existing note matching note criteria\n* If `false` then no check is performed and Note is always added",
"examples": [
true
]
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"modnote"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"referenceActivity": {
"type": "boolean"
},
"type": {
"enum": [
"ABUSE_WARNING",
"BAN",
"BOT_BAN",
"HELPFUL_USER",
"PERMA_BAN",
"SOLID_CONTRIBUTOR",
"SPAM_WARNING",
"SPAM_WATCH"
],
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"ModNoteCriteria": {
"properties": {
"activityType": {
"anyOf": [
{
"items": {
"enum": [
"comment",
false,
"submission"
]
},
"type": "array"
},
{
"enum": [
"comment",
false,
"submission"
]
}
]
},
"count": {
"default": ">= 1",
"description": "Number of occurrences of this type. Ignored if `search` is `current`\n\nA string containing a comparison operator and/or a value to compare number of occurrences against\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign] [in timeRange] [ascending|descending]`\n\nIf `timeRange` is given then only notes/mod actions that occur between timeRange and NOW will be returned. `timeRange` is ignored if search is `current`",
"examples": [
">= 1"
],
"pattern": "^\\s*(?<opStr>>|>=|<|<=)\\s*(?<value>\\d+)\\s*(?<percent>%?)\\s*(?<duration>in\\s+\\d+\\s*(days?|weeks?|months?|years?|hours?|minutes?|seconds?|milliseconds?))?\\s*(?<extra>asc.*|desc.*)*$",
"type": "string"
},
"note": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"noteType": {
"anyOf": [
{
"items": {
"enum": [
"ABUSE_WARNING",
"BAN",
"BOT_BAN",
"HELPFUL_USER",
"PERMA_BAN",
"SOLID_CONTRIBUTOR",
"SPAM_WARNING",
"SPAM_WATCH"
],
"type": "string"
},
"type": "array"
},
{
"enum": [
"ABUSE_WARNING",
"BAN",
"BOT_BAN",
"HELPFUL_USER",
"PERMA_BAN",
"SOLID_CONTRIBUTOR",
"SPAM_WARNING",
"SPAM_WATCH"
],
"type": "string"
}
]
},
"referencesCurrentActivity": {
"type": "boolean"
},
"search": {
"default": "current",
"description": "How to test the Toolbox Notes or Mod Actions for this Author:\n\n### current\n\nOnly the most recent note is checked for criteria\n\n### total\n\n`count` comparison of mod actions/notes must be found within all history\n\n* EX `count: > 3` => Must have more than 3 notes of `type`, total\n* EX `count: <= 25%` => Must have 25% or less of notes of `type`, total\n* EX: `count: > 3 in 1 week` => Must have more than 3 notes within the last week\n\n### consecutive\n\nThe `count` **number** of mod actions/notes must be found in a row.\n\nYou may also specify the time-based order in which to search the notes by specifying `ascending (asc)` or `descending (desc)` in the `count` value. Default is `descending`\n\n* EX `count: >= 3` => Must have 3 or more notes of `type` consecutively, in descending order\n* EX `count: < 2` => Must have less than 2 notes of `type` consecutively, in descending order\n* EX `count: > 4 asc` => Must have greater than 4 notes of `type` consecutively, in ascending order",
"enum": [
"consecutive",
"current",
"total"
],
"examples": [
"current"
],
"type": "string"
},
"type": {
"anyOf": [
{
"items": {
"enum": [
"APPROVAL",
"INVITE",
"NOTE",
"REMOVAL",
"SPAM"
],
"type": "string"
},
"type": "array"
},
{
"enum": [
"APPROVAL",
"INVITE",
"NOTE",
"REMOVAL",
"SPAM"
],
"type": "string"
}
]
}
},
"type": "object"
},
"ModeratorNameCriteria": {
"properties": {
"behavior": {
"enum": [
"exclude",
"include"
],
"type": "string"
},
"name": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
}
},
"required": [
"name"
],
"type": "object"
},
"NamedCriteria<ActivityState>": {
"properties": {
"criteria": {
"$ref": "#/definitions/ActivityState"
},
"name": {
"type": "string"
}
},
"required": [
"criteria"
],
"type": "object"
},
"NamedCriteria<AuthorCriteria>": {
"properties": {
"criteria": {
"$ref": "#/definitions/AuthorCriteria"
},
"name": {
"type": "string"
}
},
"required": [
"criteria"
],
"type": "object"
},
"NamedCriteria<CommentState>": {
"properties": {
"criteria": {
"$ref": "#/definitions/CommentState"
},
"name": {
"type": "string"
}
},
"required": [
"criteria"
],
"type": "object"
},
"NamedCriteria<SubmissionState>": {
"properties": {
"criteria": {
"$ref": "#/definitions/SubmissionState"
},
"name": {
"type": "string"
}
},
"required": [
"criteria"
],
"type": "object"
},
"NamedCriteria<SubredditCriteria>": {
"properties": {
"criteria": {
"$ref": "#/definitions/SubredditCriteria"
},
"name": {
"type": "string"
}
},
"required": [
"criteria"
],
"type": "object"
},
"NamedCriteria<TypedActivityState>": {
"properties": {
"criteria": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
}
]
},
"name": {
"type": "string"
}
},
"required": [
"criteria"
],
"type": "object"
},
"NotificationConfig": {
"properties": {
"events": {
"items": {
"anyOf": [
{
"$ref": "#/definitions/NotificationEventConfig"
},
{
"items": {
"enum": [
"configUpdated",
"eventActioned",
"pollingError",
"runStateChanged"
],
"type": "string"
},
"type": "array"
}
]
},
"type": "array"
},
"providers": {
"description": "A list of notification providers (Discord, etc..) to configure. Each object in the list is one provider. Multiple of the same provider can be provided but must have different names",
"items": {
"$ref": "#/definitions/DiscordProviderConfig"
},
"type": "array"
}
},
"required": [
"events",
"providers"
],
"type": "object"
},
"NotificationEventConfig": {
"properties": {
"providers": {
"items": {
"type": "string"
},
"type": "array"
},
"types": {
"items": {
"enum": [
"configUpdated",
"eventActioned",
"pollingError",
"runStateChanged"
],
"type": "string"
},
"type": "array"
}
},
"required": [
"providers",
"types"
],
"type": "object"
},
"OccurredAt": {
"properties": {
"condition": {
"description": "A duration and how to compare it against a value\n\nThe syntax is `(< OR > OR <= OR >=) <number> <unit>` EX `> 100 days`, `<= 2 months`\n\n* EX `> 100 days` => Passes if the date being compared is before 100 days ago\n* EX `<= 2 months` => Passes if the date being compared is after or equal to 2 months\n\nUnit must be one of [DayJS Duration units](https://day.js.org/docs/en/durations/creating)\n\n[See] https://regexr.com/609n8 for example",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(days|weeks|months|years|hours|minutes|seconds|milliseconds)\\s*$",
"type": "string"
},
"testOn": {
"$ref": "#/definitions/TimeBasedSelector",
"description": "Which repost to test on\n\n* `any` -- ANY repost passing `condition` will cause this criteria to be true\n* `all` -- ALL reposts must pass `condition` for this criteria to be true"
}
},
"required": [
"condition",
"testOn"
],
"type": "object"
},
"OccurrenceTests": {
"properties": {
"count": {
"properties": {
"condition": {
"enum": [
"AND",
"OR"
],
"type": "string"
},
"test": {
"description": "An array of strings containing a comparison operator and the number of repost occurrences to compare against\n\nExamples:\n\n* `\">= 7\"` -- TRUE if 7 or more reposts were found\n* `\"< 1\"` -- TRUE if less than 0 reposts were found",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"test"
],
"type": "object"
},
"time": {
"description": "Test the time the reposts occurred at",
"properties": {
"condition": {
"default": "AND",
"description": "How to test all the specified comparisons\n\n* AND -- All criteria must be true\n* OR -- Any criteria must be true\n\nDefaults to AND",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"test": {
"description": "An array of time-based conditions to test against found reposts (test when a repost was made)",
"items": {
"$ref": "#/definitions/OccurredAt"
},
"type": "array"
}
},
"required": [
"test"
],
"type": "object"
}
},
"type": "object"
},
"PollingOptions": {
"description": "A configuration for where, how, and when to poll Reddit for Activities to process",
"examples": [
{
"interval": 20000,
"limit": 25,
"pollOn": "unmoderated"
}
],
"properties": {
"delayUntil": {
"description": "Delay processing Activity until it is `N` seconds old\n\nUseful if there are other bots that may process an Activity and you want this bot to run first/last/etc.\n\nIf the Activity is already `N` seconds old when it is initially retrieved no refresh of the Activity occurs (no API request is made) and it is immediately processed.",
"type": "number"
},
"interval": {
"default": 30,
"description": "Amount of time, in seconds, to wait between requests",
"examples": [
30
],
"type": "number"
},
"limit": {
"default": 50,
"description": "The maximum number of Activities to get on every request",
"examples": [
50
],
"type": "number"
},
"pollOn": {
"description": "What source to get Activities from. The source you choose will modify how the bots behaves so choose carefully.\n\n### unmoderated (default)\n\nActivities that have yet to be approved/removed by a mod. This includes all modqueue (reports/spam) **and new submissions**.\n\nUse this if you want the bot to act like a regular moderator and act on anything that can be seen from mod tools.\n\n**Note:** Does NOT include new comments, only comments that are reported/filtered by Automoderator. If you want to process all unmoderated AND all new comments then use some version of `polling: [\"unmoderated\",\"newComm\"]`\n\n### modqueue\n\nActivities requiring moderator review, such as reported things and items caught by the spam filter.\n\nUse this if you only want the Bot to process reported/filtered Activities.\n\n### newSub\n\nGet only `Submissions` that show up in `/r/mySubreddit/new`\n\nUse this if you want the bot to process Submissions only when:\n\n* they are not initially filtered by Automoderator or\n* after they have been manually approved from modqueue\n\n### newComm\n\nGet only new `Comments`\n\nUse this if you want the bot to process Comments only when:\n\n* they are not initially filtered by Automoderator or\n* after they have been manually approved from modqueue",
"enum": [
"modqueue",
"newComm",
"newSub",
"unmoderated"
],
"type": "string"
}
},
"required": [
"pollOn"
],
"type": "object"
},
"PostBehavior": {
"properties": {
"postFail": {
"anyOf": [
{
"$ref": "#/definitions/PostBehaviorOptionConfig"
},
{
"type": "string"
}
],
"default": "next",
"description": "Do this behavior if a Check is NOT triggered"
},
"postTrigger": {
"anyOf": [
{
"$ref": "#/definitions/PostBehaviorOptionConfig"
},
{
"type": "string"
}
],
"default": "nextRun",
"description": "Do this behavior if a Check is triggered"
}
},
"type": "object"
},
"PostBehaviorOptionConfig": {
"properties": {
"behavior": {
"description": "The possible behaviors that can occur after a check has run\n\n* next => continue to next Check/Run\n* stop => stop CM lifecycle for this activity (immediately end)\n* nextRun => skip any remaining Checks in this Run and start the next Run\n* goto:[path] => specify a run[.check] to jump to",
"type": "string"
},
"recordTo": {
"anyOf": [
{
"items": {
"description": "Possible outputs to store event details to",
"enum": [
"database",
"influx"
],
"type": "string"
},
"type": "array"
},
{
"enum": [
"database",
false,
"influx",
true
]
}
],
"description": "Possible options for output:\n\n* true -> store to all\n* false -> store to none\n* string -> store to this one output\n* list -> store to these specified outputs"
}
},
"type": "object"
},
"PreHistoryFiltersConfig": {
"properties": {
"activityState": {
"$ref": "#/definitions/FilterOptionsConfig<ActivityState>",
"description": "When present, will only return Activities (Comment or Submission) retrieved from history that pass this filter"
},
"commentState": {
"$ref": "#/definitions/FilterOptionsConfig<CommentState>",
"description": "When present, will only return Comments retrieved from history that pass this filter\n\nTakes precedence over `activityState`"
},
"debug": {
"description": "Output individual filter results for each Activity tested to debug\n\nIf present overrides `debug` set at window level.",
"type": "boolean"
},
"max": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"type": [
"string",
"number"
]
}
]
},
"submissionState": {
"$ref": "#/definitions/FilterOptionsConfig<SubmissionState>",
"description": "When present, will only return Submissions retrieved from history that pass this filter\n\nTakes precedence over `activityState`"
},
"subreddits": {
"$ref": "#/definitions/FilterOptionsJson<SubredditCriteria>",
"description": "Filter Activities based on their Subreddit."
}
},
"required": [
"max"
],
"type": "object"
},
"RecentActivityRuleJSONConfig": {
"description": "Checks a user's history for any Activity (Submission/Comment) in the subreddits specified in thresholds\n\nAvailable data for [Action templating](https://github.com/FoxxMD/context-mod#action-templating):\n\n```\nsummary => comma-deliminated list of subreddits that hit the threshold and their count EX subredditA(1), subredditB(4),...\nsubCount => Total number of subreddits that hit the threshold\ntotalCount => Total number of all activity occurrences in subreddits\n```",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"imageDetection": {
"$ref": "#/definitions/ImageDetection",
"description": "When comparing submissions detect if the reference submission is an image and do a pixel-comparison to other detected image submissions.\n\n**Note:** This is an **experimental feature**"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The kind of rule to run",
"enum": [
"recentActivity"
],
"examples": [
"recentActivity"
],
"type": "string"
},
"lookAt": {
"deprecationMessage": "use `window.fetch` instead",
"description": "DEPRECATED - use `window.fetch` instead\n\nIf present restricts the activities that are considered for count from SubThreshold",
"enum": [
"comments",
"submissions"
],
"examples": [
"submissions",
"comments"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this rule. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes\n\nname is used to reference Rule result data during Action content templating. See CommentAction or ReportAction for more details.",
"examples": [
"myNewRule"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"thresholds": {
"description": "A list of subreddits/count criteria that may trigger this rule. ANY SubThreshold will trigger this rule.",
"items": {
"$ref": "#/definitions/ActivityThreshold"
},
"minItems": 1,
"type": "array"
},
"useSubmissionAsReference": {
"default": true,
"description": "When Activity is a submission should we only include activities that are other submissions with the same content?\n\n* When the Activity is a submission this defaults to **true**\n* When the Activity is a comment it is ignored (not relevant)",
"type": "boolean"
},
"window": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"$ref": "#/definitions/FullActivityWindowConfig"
},
{
"type": [
"string",
"number"
]
}
],
"description": "A value to define the range of Activities to retrieve.\n\nAcceptable values:\n\n**`ActivityWindowCriteria` object**\n\nAllows specify multiple range properties and more specific behavior\n\n**A `number` of Activities to retrieve**\n\n* EX `100` => 100 Activities\n\n*****\n\nAny of the below values that specify the amount of time to subtract from `NOW` to create a time range IE `NOW <---> [duration] ago`\n\nAcceptable values:\n\n**A `string` consisting of a value and a [Day.js](https://day.js.org/docs/en/durations/creating#list-of-all-available-units) time UNIT**\n\n* EX `9 days` => Range is `NOW <---> 9 days ago`\n\n**A [Day.js](https://day.js.org/docs/en/durations/creating) `object`**\n\n* EX `{\"days\": 90, \"minutes\": 15}` => Range is `NOW <---> 90 days and 15 minutes ago`\n\n**An [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) `string`**\n\n* EX `PT15M` => 15 minutes => Range is `NOW <----> 15 minutes ago`",
"examples": [
"90 days"
]
}
},
"required": [
"kind",
"thresholds"
],
"type": "object"
},
"RegExp": {
"properties": {
"dotAll": {
"type": "boolean"
},
"flags": {
"type": "string"
},
"global": {
"type": "boolean"
},
"ignoreCase": {
"type": "boolean"
},
"lastIndex": {
"type": "number"
},
"multiline": {
"type": "boolean"
},
"source": {
"type": "string"
},
"sticky": {
"type": "boolean"
},
"unicode": {
"type": "boolean"
}
},
"required": [
"dotAll",
"flags",
"global",
"ignoreCase",
"lastIndex",
"multiline",
"source",
"sticky",
"unicode"
],
"type": "object"
},
"RegexCriteria": {
"properties": {
"activityMatchThreshold": {
"default": "> 0",
"description": "An string containing a comparison operator and a value to determine how many Activities need to be \"matched\" (based on `matchThreshold` condition) to trigger the rule\n\n**Only useful when used in conjunction with `window`**. If no `window` is specified only the Activity being checked is tested (so the default should/will be used).\n\nTo disable (you are only using `totalMatchThreshold`) set to `null`\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign]`\n\n* EX `> 3` => greater than 3 Activities met the `matchThreshold` condition, Rule is triggered\n* EX `<= 10%` => less than 10% of all Activities retrieved from `window` met the `matchThreshold` condition, Rule is triggered",
"examples": [
"> 0"
],
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"lookAt": {
"default": "all",
"deprecationMessage": "use `window.fetch` instead",
"description": "DEPRECATED - use `window.fetch` instead\n\nWhen used with `window` determines what type of Activities to retrieve",
"enum": [
"all",
"comments",
"submissions"
],
"type": "string"
},
"matchThreshold": {
"default": "> 0",
"description": "A string containing a comparison operator and a value to determine when an Activity is determined \"matched\"\n\nThe syntax is `(< OR > OR <= OR >=) <number>`\n\n* EX `> 7 => greater than 7 matches found in the Activity, Activity is matched\n* EX `<= 3` => less than 3 matches found in the Activity, Activity is matched",
"examples": [
"> 0"
],
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)(\\s+.*)*$",
"type": "string"
},
"mustMatchCurrent": {
"default": false,
"description": "When `true` the Activity being checked MUST pass the `matchThreshold` before the Rule considers any history\n\nFor use with `activityMatchThreshold`/`totalMatchThreshold` -- useful to conserve API calls",
"type": "boolean"
},
"name": {
"description": "A descriptive name that will be used in logging and be available for templating",
"examples": [
"swear words"
],
"type": "string"
},
"regex": {
"description": "A valid Regular Expression to test content against\n\nIf no flags are specified then the **global** flag is used by default",
"examples": [
"/reddit|FoxxMD/ig"
],
"type": "string"
},
"testOn": {
"default": [
"title",
"body"
],
"description": "Which content from an Activity to test the regex against\n\nOnly used if the Activity being tested is a Submission -- Comments are only tested against their content (duh)",
"items": {
"enum": [
"body",
"title",
"url"
],
"type": "string"
},
"type": "array"
},
"totalMatchThreshold": {
"default": "null",
"description": "A string containing a comparison operator and a value to determine how many total matches satisfies the criteria.\n\nIf both this and `activityMatchThreshold` are present then whichever is satisfied first will be used.\n\nIf not using `window` then this should not be used as running `matchThreshold` on one Activity is effectively the same behavior ( but I'm not gonna stop ya ¯\\\\\\_(ツ)\\_/¯ )\n\nThe syntax is `(< OR > OR <= OR >=) <number>`\n\n* EX `> 7` => greater than 7 matches found in Activity + Author history `window`\n* EX `<= 3` => less than 3 matches found in the Activity + Author history `window`",
"examples": [
"> 0"
],
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)(\\s+.*)*$",
"type": "string"
},
"window": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"$ref": "#/definitions/FullActivityWindowConfig"
},
{
"type": [
"string",
"number"
]
}
],
"description": "A value to define the range of Activities to retrieve.\n\nAcceptable values:\n\n**`ActivityWindowCriteria` object**\n\nAllows specify multiple range properties and more specific behavior\n\n**A `number` of Activities to retrieve**\n\n* EX `100` => 100 Activities\n\n*****\n\nAny of the below values that specify the amount of time to subtract from `NOW` to create a time range IE `NOW <---> [duration] ago`\n\nAcceptable values:\n\n**A `string` consisting of a value and a [Day.js](https://day.js.org/docs/en/durations/creating#list-of-all-available-units) time UNIT**\n\n* EX `9 days` => Range is `NOW <---> 9 days ago`\n\n**A [Day.js](https://day.js.org/docs/en/durations/creating) `object`**\n\n* EX `{\"days\": 90, \"minutes\": 15}` => Range is `NOW <---> 90 days and 15 minutes ago`\n\n**An [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) `string`**\n\n* EX `PT15M` => 15 minutes => Range is `NOW <----> 15 minutes ago`",
"examples": [
"90 days"
]
}
},
"required": [
"regex"
],
"type": "object"
},
"RegexRuleJSONConfig": {
"description": "Test a (list of) Regular Expression against the contents or title of an Activity\n\nOptionally, specify a `window` of the User's history to additionally test against\n\nAvailable data for [Action templating](https://github.com/FoxxMD/context-mod#action-templating):",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"condition": {
"default": "OR",
"description": "* If `OR` then any set of Criteria that pass will trigger the Rule\n* If `AND` then all Criteria sets must pass to trigger the Rule",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"criteria": {
"description": "A list of Regular Expressions and conditions under which tested Activity(ies) are matched",
"examples": [
{
"matchThreshold": "> 3",
"regex": "/reddit/"
}
],
"items": {
"$ref": "#/definitions/RegexCriteria"
},
"minItems": 1,
"type": "array"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The kind of rule to run",
"enum": [
"regex"
],
"examples": [
"regex"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this rule. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes\n\nname is used to reference Rule result data during Action content templating. See CommentAction or ReportAction for more details.",
"examples": [
"myNewRule"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
}
},
"required": [
"criteria",
"kind"
],
"type": "object"
},
"RemoveActionJson": {
"description": "Remove the Activity",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"remove"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"note": {
"description": "(Optional) A mod-readable note added to the removal reason for this Activity. Can use Templating.\n\nThis note (and removal reasons) are only visible on New Reddit",
"type": "string"
},
"reasonId": {
"description": "(Optional) The ID of the Removal Reason to use\n\nRemoval reasons are only visible on New Reddit\n\nTo find IDs for removal reasons check the \"Removal Reasons\" popup located in the CM dashboard config editor for your subreddit\n\nMore info on Removal Reasons: https://mods.reddithelp.com/hc/en-us/articles/360010094892-Removal-Reasons",
"type": "string"
},
"spam": {
"description": "(Optional) Mark Activity as spam",
"type": "boolean"
}
},
"required": [
"kind"
],
"type": "object"
},
"RepeatActivityJSONConfig": {
"description": "Checks a user's history for Submissions with identical content\n\nAvailable data for [Action templating](https://github.com/FoxxMD/context-mod#action-templating):\n\n```\ncount => Total number of repeat Submissions\nthreshold => The threshold you configured for this Rule to trigger\nurl => Url of the submission that triggered the rule\n```",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"caseSensitive": {
"default": false,
"description": "Should text matching be case sensitive?\n\nDefaults to false",
"type": "boolean"
},
"exclude": {
"description": "If present, activities will be counted only if they are **NOT** found in this list of Subreddits\n\nEach value in the list can be either:\n\n * string (name of subreddit)\n * regular expression to run on the subreddit name\n * `SubredditState`\n\nEX `[\"mealtimevideos\",\"askscience\", \"/onlyfans*\\/i\", {\"over18\": true}]`",
"examples": [
[
"mealtimevideos",
"askscience",
"/onlyfans*/i",
{
"over18": true
}
]
],
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubredditCriteria"
},
{
"type": "string"
}
]
},
"type": "array"
},
"gapAllowance": {
"description": "The number of allowed non-identical Submissions between identical Submissions that can be ignored when checking against the threshold value",
"type": "number"
},
"include": {
"description": "If present, activities will be counted only if they are found in this list of Subreddits\n\nEach value in the list can be either:\n\n * string (name of subreddit)\n * regular expression to run on the subreddit name\n * `SubredditState`\n\nEX `[\"mealtimevideos\",\"askscience\", \"/onlyfans*\\/i\", {\"over18\": true}]`",
"examples": [
[
"mealtimevideos",
"askscience",
"/onlyfans*/i",
{
"over18": true
}
]
],
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubredditCriteria"
},
{
"type": "string"
}
]
},
"type": "array"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"keepRemoved": {
"default": false,
"description": "Count submissions/comments that have previously been removed.\n\nBy default all `Submissions/Commments` that are in a `removed` state will be filtered from `window` (only applies to subreddits you mod).\n\nSetting to `true` could be useful if you also want to also detected removed repeat posts by a user like for example if automoderator removes multiple, consecutive submissions for not following title format correctly.",
"type": "boolean"
},
"kind": {
"description": "The kind of rule to run",
"enum": [
"repeatActivity"
],
"type": "string"
},
"lookAt": {
"default": "all",
"description": "If present determines which activities to consider for gapAllowance.\n\n* If `submissions` then only the author's submission history is considered IE gapAllowance = 2 ===> can have gap of two submissions between repeats\n* If `all` then the author's entire history (submissions/comments) is considered IE gapAllowance = 2 ===> can only have gap of two activities (submissions or comments) between repeats",
"enum": [
"all",
"submissions"
],
"type": "string"
},
"matchScore": {
"default": 85,
"description": "The percentage, as a whole number, of a repost title/comment that must match the title/comment being checked in order to consider both a match\n\nNote: Setting to 0 will make every candidate considered a match -- useful if you want to match if the URL has been reposted anywhere\n\nDefaults to `85` (85%)",
"type": "number"
},
"minWordCount": {
"default": 2,
"description": "The minimum number of words in the activity being checked for which this rule will run on\n\nIf the word count is below the minimum the rule fails\n\nDefaults to 2",
"type": "number"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this rule. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes\n\nname is used to reference Rule result data during Action content templating. See CommentAction or ReportAction for more details.",
"examples": [
"myNewRule"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"threshold": {
"default": ">= 5",
"description": "The number of repeat submissions that will trigger the rule",
"type": "string"
},
"transformations": {
"description": "A set of search-and-replace operations to perform on text values before performing a match. Transformations are performed in the order they are defined.",
"items": {
"$ref": "#/definitions/SearchAndReplaceRegExp"
},
"type": "array"
},
"useSubmissionAsReference": {
"default": true,
"description": "If activity is a Submission and is a link (not self-post) then only look at Submissions that contain this link, otherwise consider all activities.",
"type": "boolean"
},
"window": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"$ref": "#/definitions/FullActivityWindowConfig"
},
{
"type": [
"string",
"number"
]
}
],
"description": "A value to define the range of Activities to retrieve.\n\nAcceptable values:\n\n**`ActivityWindowCriteria` object**\n\nAllows specify multiple range properties and more specific behavior\n\n**A `number` of Activities to retrieve**\n\n* EX `100` => 100 Activities\n\n*****\n\nAny of the below values that specify the amount of time to subtract from `NOW` to create a time range IE `NOW <---> [duration] ago`\n\nAcceptable values:\n\n**A `string` consisting of a value and a [Day.js](https://day.js.org/docs/en/durations/creating#list-of-all-available-units) time UNIT**\n\n* EX `9 days` => Range is `NOW <---> 9 days ago`\n\n**A [Day.js](https://day.js.org/docs/en/durations/creating) `object`**\n\n* EX `{\"days\": 90, \"minutes\": 15}` => Range is `NOW <---> 90 days and 15 minutes ago`\n\n**An [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) `string`**\n\n* EX `PT15M` => 15 minutes => Range is `NOW <----> 15 minutes ago`",
"examples": [
"90 days"
]
}
},
"required": [
"kind"
],
"type": "object"
},
"ReportActionJson": {
"description": "Report the Activity",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"content": {
"description": "The Content to submit for this Action. Content is interpreted as reddit-flavored Markdown.\n\nIf value starts with `wiki:` then the proceeding value will be used to get a wiki page from the current subreddit\n\n * EX `wiki:botconfig/mybot` tries to get `https://reddit.com/r/currentSubreddit/wiki/botconfig/mybot`\n\nIf the value starts with `wiki:` and ends with `|someValue` then `someValue` will be used as the base subreddit for the wiki page\n\n* EX `wiki:replytemplates/test|ContextModBot` tries to get `https://reddit.com/r/ContextModBot/wiki/replytemplates/test`\n\nIf the value starts with `url:` then the value is fetched as an external url and expects raw text returned\n\n* EX `url:https://pastebin.com/raw/38qfL7mL` tries to get the text response of `https://pastebin.com/raw/38qfL7mL`\n\nIf none of the above is used the value is treated as the raw context\n\n * EX `this is **bold** markdown text` => \"this is **bold** markdown text\"\n\nAll Content is rendered using [mustache](https://github.com/janl/mustache.js/#templates) to enable [Action Templating](https://github.com/FoxxMD/context-mod#action-templating).\n\nThe following properties are always available in the template (view individual Rules to see rule-specific template data):\n```\nitem.kind => The type of Activity that was checked (comment/submission)\nitem.author => The name of the Author of the Activity EX FoxxMD\nitem.permalink => A permalink URL to the Activity EX https://reddit.com/r/yourSub/comments/o1h0i0/title_name/1v3b7x\nitem.url => If the Activity is Link Sumbission then the external URL\nitem.title => If the Activity is a Submission then the title of that Submission\nrules => An object containing RuleResults of all the rules run for this check. See Action Templating for more details on naming\n```",
"examples": [
"This is the content of a comment/report/usernote",
"this is **bold** markdown text",
"wiki:botconfig/acomment"
],
"type": "string"
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"report"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"RepostCriteria": {
"description": "A set of criteria used to find reposts\n\nContains options and conditions used to define how candidate reposts are retrieved and if they are a match.",
"properties": {
"caseSensitive": {
"default": false,
"description": "Should text matching be case sensitive?\n\nDefaults to false",
"type": "boolean"
},
"matchScore": {
"default": 85,
"description": "The percentage, as a whole number, of a repost title/comment that must match the title/comment being checked in order to consider both a match\n\nNote: Setting to 0 will make every candidate considered a match -- useful if you want to match if the URL has been reposted anywhere\n\nDefaults to `85` (85%)",
"type": "number"
},
"maxExternalItems": {
"default": 50,
"description": "The maximum number of external items (youtube comments) to check (and cache for comment checks)",
"type": "number"
},
"maxRedditItems": {
"default": 50,
"description": "The maximum number of comments/submissions to check\n\nIn both cases this list is gathered from sorting all submissions or all comments from all submission by number of votes and taking the \"top\" maximum specified\n\nFor comment checks this is the number of comments cached",
"type": "number"
},
"minWordCount": {
"default": 2,
"description": "The minimum number of words in the activity being checked for which this rule will run on\n\nIf the word count is below the minimum the rule fails\n\nDefaults to 2",
"type": "number"
},
"occurredAt": {
"description": "Test the time the reposts occurred at",
"properties": {
"condition": {
"default": "AND",
"description": "How to test all the specified comparisons\n\n* AND -- All criteria must be true\n* OR -- Any criteria must be true\n\nDefaults to AND",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"criteria": {
"description": "An array of time-based conditions to test against found reposts (test when a repost was made)",
"items": {
"$ref": "#/definitions/OccurredAt"
},
"type": "array"
}
},
"required": [
"criteria"
],
"type": "object"
},
"occurrences": {
"description": "A set of comparisons to test against the number of reposts found\n\nIf not specified the default is \"AND [occurrences] > 0\" IE any reposts makes this test pass",
"properties": {
"condition": {
"default": "AND",
"description": "How to test all the specified comparisons\n\n* AND -- All criteria must be true\n* OR -- Any criteria must be true\n\nDefaults to AND",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"criteria": {
"items": {
"$ref": "#/definitions/OccurrenceTests"
},
"type": "array"
}
},
"type": "object"
},
"searchOn": {
"description": "Define how to find candidate reposts\n\n* **title** -- search reddit for submissions with the same title\n* **url** -- search reddit for submissions with the same url\n* **external** -- WHEN ACTIVITY IS A COMMENT - tries to get comments from external source (youtube, twitter, etc...)",
"items": {
"anyOf": [
{
"$ref": "#/definitions/SearchFacetJSONConfig"
},
{
"enum": [
"crossposts",
"duplicates",
"external",
"title",
"url"
],
"type": "string"
}
]
},
"type": "array"
},
"transformations": {
"description": "A set of search-and-replace operations to perform on text values before performing a match. Transformations are performed in the order they are defined.\n\n* If `transformationsActivity` IS NOT defined then these transformations will be performed on BOTH the activity text (submission title or comment) AND the repost candidate text\n* If `transformationsActivity` IS defined then these transformations are only performed on repost candidate text",
"items": {
"$ref": "#/definitions/SearchAndReplaceRegExp"
},
"type": "array"
},
"transformationsActivity": {
"description": "Specify a separate set of transformations for the activity text (submission title or comment)\n\nTo perform no transformations when `transformations` is defined set this to an empty array (`[]`)",
"items": {
"$ref": "#/definitions/SearchAndReplaceRegExp"
},
"type": "array"
},
"window": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"$ref": "#/definitions/FullActivityWindowConfig"
},
{
"type": [
"string",
"number"
]
}
],
"description": "A value to define the range of Activities to retrieve.\n\nAcceptable values:\n\n**`ActivityWindowCriteria` object**\n\nAllows specify multiple range properties and more specific behavior\n\n**A `number` of Activities to retrieve**\n\n* EX `100` => 100 Activities\n\n*****\n\nAny of the below values that specify the amount of time to subtract from `NOW` to create a time range IE `NOW <---> [duration] ago`\n\nAcceptable values:\n\n**A `string` consisting of a value and a [Day.js](https://day.js.org/docs/en/durations/creating#list-of-all-available-units) time UNIT**\n\n* EX `9 days` => Range is `NOW <---> 9 days ago`\n\n**A [Day.js](https://day.js.org/docs/en/durations/creating) `object`**\n\n* EX `{\"days\": 90, \"minutes\": 15}` => Range is `NOW <---> 90 days and 15 minutes ago`\n\n**An [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) `string`**\n\n* EX `PT15M` => 15 minutes => Range is `NOW <----> 15 minutes ago`",
"examples": [
"90 days"
]
}
},
"type": "object"
},
"RepostRuleJSONConfig": {
"description": "Search for reposts of a Submission or Comment\n\n* For submissions the title or URL can searched and matched against\n* For comments, candidate comments are gathered from similar reddit submissions and/or external sources (youtube, twitter, etc..) and then matched against",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"condition": {
"default": "OR",
"description": "* If `OR` then any set of Criteria that pass will trigger the Rule\n* If `AND` then all Criteria sets must pass to trigger the Rule",
"enum": [
"AND",
"OR"
],
"type": "string"
},
"criteria": {
"description": "A list of Regular Expressions and conditions under which tested Activity(ies) are matched",
"examples": [
{
"matchThreshold": "> 3",
"regex": "/reddit/"
}
],
"items": {
"$ref": "#/definitions/RepostCriteria"
},
"minItems": 1,
"type": "array"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The kind of rule to run",
"enum": [
"repost"
],
"examples": [
"repost"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this rule. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes\n\nname is used to reference Rule result data during Action content templating. See CommentAction or ReportAction for more details.",
"examples": [
"myNewRule"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"RuleSetConfigData": {
"description": "A RuleSet is a \"nested\" set of `Rule` objects that can be used to create more complex AND/OR behavior. Think of the outcome of a `RuleSet` as the result of all of its run `Rule` objects (based on `condition`)",
"properties": {
"condition": {
"default": "AND",
"description": "Under what condition should a set of run `Rule` objects be considered \"successful\"?\n\nIf `OR` then **any** triggered `Rule` object results in success.\n\nIf `AND` then **all** `Rule` objects must be triggered to result in success.",
"enum": [
"AND",
"OR"
],
"examples": [
"AND"
],
"type": "string"
},
"rules": {
"description": "Can be `Rule` or the `name` of any **named** `Rule` in your subreddit's configuration",
"items": {
"anyOf": [
{
"$ref": "#/definitions/IncludesData"
},
{
"$ref": "#/definitions/RecentActivityRuleJSONConfig"
},
{
"$ref": "#/definitions/RepeatActivityJSONConfig"
},
{
"$ref": "#/definitions/AuthorRuleJSONConfig"
},
{
"$ref": "#/definitions/AttributionJSONConfig"
},
{
"$ref": "#/definitions/HistoryJSONConfig"
},
{
"$ref": "#/definitions/RegexRuleJSONConfig"
},
{
"$ref": "#/definitions/RepostRuleJSONConfig"
},
{
"$ref": "#/definitions/SentimentRuleJSONConfig"
},
{
"$ref": "#/definitions/MHSRuleJSONConfig"
},
{
"type": "string"
}
]
},
"minItems": 1,
"type": "array"
}
},
"required": [
"rules"
],
"type": "object"
},
"RunConfigData": {
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"checks": {
"items": {
"anyOf": [
{
"$ref": "#/definitions/IncludesData"
},
{
"$ref": "#/definitions/SubmissionCheckConfigData"
},
{
"$ref": "#/definitions/CommentCheckConfigData"
},
{
"type": "string"
}
]
},
"type": "array"
},
"dryRun": {
"description": "Use this option to override the `dryRun` setting for all Actions of all Checks in this Run",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "Should this Run be executed by the bot?",
"examples": [
true
],
"type": "boolean"
},
"filterCriteriaDefaults": {
"$ref": "#/definitions/FilterCriteriaDefaultsJson",
"description": "Set the default filter criteria for all checks. If this property is specified it will override any defaults passed from the bot's config\n\nDefault behavior is to exclude all mods and automoderator from checks"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"name": {
"description": "Friendly name for this Run EX \"flairsRun\"\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myNewRun"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"postFail": {
"anyOf": [
{
"$ref": "#/definitions/PostBehaviorOptionConfig"
},
{
"type": "string"
}
],
"default": "next",
"description": "Do this behavior if a Check is NOT triggered"
},
"postTrigger": {
"anyOf": [
{
"$ref": "#/definitions/PostBehaviorOptionConfig"
},
{
"type": "string"
}
],
"default": "nextRun",
"description": "Do this behavior if a Check is triggered"
}
},
"required": [
"checks"
],
"type": "object"
},
"SearchAndReplaceRegExp": {
"properties": {
"replace": {
"description": "The replacement string/value to use when search is found\n\nThis can be a literal string like `'replace with this`, an empty string to remove the search value (`''`), or a special regex value\n\nSee replacement here for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace",
"type": "string"
},
"search": {
"description": "The search value to test for\n\nCan be a normal string (converted to a case-sensitive literal) or a valid regular expression\n\nEX `[\"find this string\", \"/some string*\\/ig\"]`",
"examples": [
"find this string",
"/some string*/ig"
],
"type": "string"
}
},
"required": [
"replace",
"search"
],
"type": "object"
},
"SearchFacetJSONConfig": {
"properties": {
"caseSensitive": {
"default": false,
"description": "Should text matching be case sensitive?\n\nDefaults to false",
"type": "boolean"
},
"kind": {
"anyOf": [
{
"items": {
"enum": [
"crossposts",
"duplicates",
"external",
"title",
"url"
],
"type": "string"
},
"type": "array"
},
{
"enum": [
"crossposts",
"duplicates",
"external",
"title",
"url"
],
"type": "string"
}
]
},
"matchScore": {
"default": 85,
"description": "The percentage, as a whole number, of a repost title/comment that must match the title/comment being checked in order to consider both a match\n\nNote: Setting to 0 will make every candidate considered a match -- useful if you want to match if the URL has been reposted anywhere\n\nDefaults to `85` (85%)",
"type": "number"
},
"minWordCount": {
"default": 2,
"description": "The minimum number of words in the activity being checked for which this rule will run on\n\nIf the word count is below the minimum the rule fails\n\nDefaults to 2",
"type": "number"
},
"transformations": {
"description": "A set of search-and-replace operations to perform on text values before performing a match. Transformations are performed in the order they are defined.\n\n* If `transformationsActivity` IS NOT defined then these transformations will be performed on BOTH the activity text (submission title or comment) AND the repost candidate text\n* If `transformationsActivity` IS defined then these transformations are only performed on repost candidate text",
"items": {
"$ref": "#/definitions/SearchAndReplaceRegExp"
},
"type": "array"
},
"transformationsActivity": {
"description": "Specify a separate set of transformations for the activity text (submission title or comment)\n\nTo perform no transformations when `transformations` is defined set this to an empty array (`[]`)",
"items": {
"$ref": "#/definitions/SearchAndReplaceRegExp"
},
"type": "array"
},
"window": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"$ref": "#/definitions/FullActivityWindowConfig"
},
{
"type": [
"string",
"number"
]
}
],
"description": "A value to define the range of Activities to retrieve.\n\nAcceptable values:\n\n**`ActivityWindowCriteria` object**\n\nAllows specify multiple range properties and more specific behavior\n\n**A `number` of Activities to retrieve**\n\n* EX `100` => 100 Activities\n\n*****\n\nAny of the below values that specify the amount of time to subtract from `NOW` to create a time range IE `NOW <---> [duration] ago`\n\nAcceptable values:\n\n**A `string` consisting of a value and a [Day.js](https://day.js.org/docs/en/durations/creating#list-of-all-available-units) time UNIT**\n\n* EX `9 days` => Range is `NOW <---> 9 days ago`\n\n**A [Day.js](https://day.js.org/docs/en/durations/creating) `object`**\n\n* EX `{\"days\": 90, \"minutes\": 15}` => Range is `NOW <---> 90 days and 15 minutes ago`\n\n**An [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) `string`**\n\n* EX `PT15M` => 15 minutes => Range is `NOW <----> 15 minutes ago`",
"examples": [
"90 days"
]
}
},
"required": [
"kind"
],
"type": "object"
},
"SentimentRuleJSONConfig": {
"description": "Test the calculated VADER sentiment for an Activity to determine if the text context is negative, neutral, or positive in tone.\n\nMore about VADER Sentiment: https://github.com/cjhutto/vaderSentiment",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"defaultLanguage": {
"anyOf": [
{
"enum": [
false
],
"type": "boolean"
},
{
"type": [
"null",
"string"
]
}
],
"default": "en",
"description": "Make the analyzer assume a language if it cannot determine one itself.\n\nThis is very useful for the analyzer when it is parsing short pieces of content. For example, if you know your subreddit is majority english speakers this will make the analyzer return \"neutral\" sentiment instead of \"not detected language\".\n\nDefaults to 'en'"
},
"historical": {
"$ref": "#/definitions/HistoricalSentimentConfig",
"description": "Test the Sentiment of Activities from the Author history\n\nIf this is defined then the `totalMatching` threshold must pass for the Rule to trigger\n\nIf `sentiment` is defined here it overrides the top-level `sentiment` value"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The kind of rule to run",
"enum": [
"sentiment"
],
"examples": [
"sentiment"
],
"type": "string"
},
"languageHints": {
"default": [
"en",
"es",
"de",
"fr"
],
"description": "Helps the analyzer coerce a low confidence language guess into a known-used languages in two ways:\n\nIf the analyzer's\n * *best* guess is NOT one of these\n * but it did guess one of these\n * and its guess is above requiredLanguageConfidence score then use the hinted language instead of best guess\n * OR text content is very short (4 words or less)\n * and the best guess was below the requiredLanguageConfidence score\n * and none of guesses was a hinted language then use the defaultLanguage\n\nDefaults to popular romance languages: ['en', 'es', 'de', 'fr']",
"items": {
"type": "string"
},
"type": "array"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this rule. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes\n\nname is used to reference Rule result data during Action content templating. See CommentAction or ReportAction for more details.",
"examples": [
"myNewRule"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"requiredLanguageConfidence": {
"default": 0.9,
"description": "Required confidence to use a guessed language as the best guess. Score from 0 to 1.\n\nDefaults to 0.9",
"type": "number"
},
"sentiment": {
"description": "Test the calculated VADER sentiment (compound) score for an Activity using this comparison. Can be either a numerical or natural language\n\nSentiment values range from extremely negative to extremely positive in a numerical range of -1 to +1:\n\n* -0.6 => extremely negative\n* -0.3 => very negative\n* -0.1 => negative\n* 0 => neutral\n* 0.1 => positive\n* 0.3 => very positive\n* 0.6 => extremely positive\n\nThe below examples are all equivocal. You can use either set of values as the value for `sentiment` (numerical comparisons or natural langauge)\n\n* `>= 0.1` = `is positive`\n* `<= 0.3` = `is very negative`\n* `< 0.1` = `is not positive`\n* `> -0.3` = `is not very negative`\n\nSpecial case:\n\n* `is neutral` equates to `> -0.1 and < 0.1`\n* `is not neutral` equates to `< -0.1 or > 0.1`\n\nContextMod uses a normalized, weighted average from these sentiment tools:\n\n* NLP.js (english, french, german, and spanish) https://github.com/axa-group/nlp.js/blob/master/docs/v3/sentiment-analysis.md\n* (english only) vaderSentiment-js https://github.com/vaderSentiment/vaderSentiment-js/\n* (english only) wink-sentiment https://github.com/winkjs/wink-sentiment\n\nMore about the sentiment algorithms used:\n* VADER https://github.com/cjhutto/vaderSentiment\n* AFINN http://corpustext.com/reference/sentiment_afinn.html\n* Senticon https://ieeexplore.ieee.org/document/8721408\n* Pattern https://github.com/clips/pattern\n* wink https://github.com/winkjs/wink-sentiment",
"examples": [
"is negative",
"> 0.2"
],
"pattern": "((>|>=|<|<=)\\s*(-?\\d?\\.?\\d+))|((not)?\\s*(very|extremely)?\\s*(positive|neutral|negative))",
"type": "string"
},
"testOn": {
"default": [
"title",
"body"
],
"description": "Which content from an Activity to test for `sentiment` against\n\nOnly used if the Activity being tested is a Submission -- Comments are only tested against their body\n\nIf more than one type of content is specified then all text is tested together as one string",
"items": {
"enum": [
"body",
"title"
],
"type": "string"
},
"type": "array"
}
},
"required": [
"kind",
"sentiment"
],
"type": "object"
},
"SharingACLConfig": {
"properties": {
"exclude": {
"description": "A list of subreddits, or regular expressions for subreddit names, that are NOT allowed to access this config\n\nIf `include` is defined this property is ignored",
"items": {
"type": "string"
},
"type": "array"
},
"include": {
"description": "A list of subreddits, or regular expressions for subreddit names, that are allowed to access this config",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"SubmissionActionJson": {
"description": "Reply to the Activity. For a submission the reply will be a top-level comment.",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"content": {
"description": "The Content to submit for this Action. Content is interpreted as reddit-flavored Markdown.\n\nIf value starts with `wiki:` then the proceeding value will be used to get a wiki page from the current subreddit\n\n * EX `wiki:botconfig/mybot` tries to get `https://reddit.com/r/currentSubreddit/wiki/botconfig/mybot`\n\nIf the value starts with `wiki:` and ends with `|someValue` then `someValue` will be used as the base subreddit for the wiki page\n\n* EX `wiki:replytemplates/test|ContextModBot` tries to get `https://reddit.com/r/ContextModBot/wiki/replytemplates/test`\n\nIf the value starts with `url:` then the value is fetched as an external url and expects raw text returned\n\n* EX `url:https://pastebin.com/raw/38qfL7mL` tries to get the text response of `https://pastebin.com/raw/38qfL7mL`\n\nIf none of the above is used the value is treated as the raw context\n\n * EX `this is **bold** markdown text` => \"this is **bold** markdown text\"\n\nAll Content is rendered using [mustache](https://github.com/janl/mustache.js/#templates) to enable [Action Templating](https://github.com/FoxxMD/context-mod#action-templating).\n\nThe following properties are always available in the template (view individual Rules to see rule-specific template data):\n```\nitem.kind => The type of Activity that was checked (comment/submission)\nitem.author => The name of the Author of the Activity EX FoxxMD\nitem.permalink => A permalink URL to the Activity EX https://reddit.com/r/yourSub/comments/o1h0i0/title_name/1v3b7x\nitem.url => If the Activity is Link Sumbission then the external URL\nitem.title => If the Activity is a Submission then the title of that Submission\nrules => An object containing RuleResults of all the rules run for this check. See Action Templating for more details on naming\n```",
"examples": [
"This is the content of a comment/report/usernote",
"this is **bold** markdown text",
"wiki:botconfig/acomment"
],
"type": "string"
},
"distinguish": {
"description": "Distinguish as Mod after creation?",
"type": "boolean"
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"flairId": {
"description": "Flair template to apply to this Submission",
"type": "string"
},
"flairText": {
"description": "Flair text to apply to this Submission",
"type": "string"
},
"footer": {
"anyOf": [
{
"enum": [
false
],
"type": "boolean"
},
{
"type": "string"
}
],
"description": "Customize the footer for Actions that send replies (Comment/Ban)\n\nIf `false` no footer is appended\n\nIf `string` the value is rendered as markdown or will use `wiki:` parser the same way `content` properties on Actions are rendered with [templating](https://github.com/FoxxMD/context-mod#action-templating).\n\nIf footer is `undefined` (not set) the default footer will be used:\n\n> *****\n> This action was performed by [a bot.] Mention a moderator or [send a modmail] if you any ideas, questions, or concerns about this action.\n\n*****\n\nThe following properties are available for [templating](https://github.com/FoxxMD/context-mod#action-templating):\n```\nsubName => name of subreddit Action was performed in (EX 'mealtimevideos')\npermaLink => The permalink for the Activity the Action was performed on EX https://reddit.com/r/yourSub/comments/o1h0i0/title_name/1v3b7x\nmodmaiLink => An encoded URL that will open a new message to your subreddit with the Action permalink appended to the body\nbotLink => A permalink to the FAQ for this bot.\n```\nIf you use your own footer or no footer **please link back to the bot FAQ** using the `{{botLink}}` property in your content :)"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"submission"
],
"type": "string"
},
"lock": {
"description": "Lock the Submission after creation?",
"type": "boolean"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"nsfw": {
"type": "boolean"
},
"spoiler": {
"type": "boolean"
},
"sticky": {
"description": "Sticky the Submission after creation?",
"type": "boolean"
},
"targets": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "Specify where this Submission should be made\n\nValid values: 'self' | [subreddit]\n\n* 'self' -- DEFAULT. Post Submission to same subreddit of Activity being processed\n* [subreddit] -- The name of a subreddit to post Submission to. EX mealtimevideos"
},
"title": {
"description": "The title of this Submission.\n\nTemplated the same as **content**",
"type": "string"
},
"url": {
"description": "If Submission should be a Link, the URL to use\n\nTemplated the same as **content**\n\nPROTIP: To make a Link Submission pointing to the Activity being processed use `{{item.permalink}}` as the URL value",
"type": "string"
}
},
"required": [
"kind",
"title"
],
"type": "object"
},
"SubmissionCheckConfigData": {
"properties": {
"actions": {
"description": "The `Actions` to run after the check is successfully triggered. ALL `Actions` will run in the order they are listed\n\n Can be `Action` or the `name` of any **named** `Action` in your subreddit's configuration",
"examples": [
[
{
"content": "this is the content of the comment",
"distinguish": true,
"kind": "comment"
},
{
"kind": "lock"
}
]
],
"items": {
"anyOf": [
{
"$ref": "#/definitions/IncludesData"
},
{
"$ref": "#/definitions/FlairActionJson"
},
{
"$ref": "#/definitions/UserFlairActionJson"
},
{
"$ref": "#/definitions/CommentActionJson"
},
{
"$ref": "#/definitions/ReportActionJson"
},
{
"$ref": "#/definitions/LockActionJson"
},
{
"$ref": "#/definitions/RemoveActionJson"
},
{
"$ref": "#/definitions/UserNoteActionJson"
},
{
"$ref": "#/definitions/ApproveActionJson"
},
{
"$ref": "#/definitions/BanActionJson"
},
{
"$ref": "#/definitions/MessageActionJson"
},
{
"$ref": "#/definitions/DispatchActionJson"
},
{
"$ref": "#/definitions/CancelDispatchActionJson"
},
{
"$ref": "#/definitions/ContributorActionJson"
},
{
"$ref": "#/definitions/ModNoteActionJson"
},
{
"$ref": "#/definitions/SubmissionActionJson"
},
{
"type": "string"
}
]
},
"type": "array"
},
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"cacheUserResult": {
"$ref": "#/definitions/UserResultCacheOptions",
"description": "Cache the result of this check based on the comment author and the submission id\n\nThis is useful in this type of scenario:\n\n1. This check is configured to run on comments for specific submissions with high volume activity\n2. The rules being run are not dependent on the content of the comment\n3. The rule results are not likely to change while cache is valid"
},
"condition": {
"default": "AND",
"description": "Under what condition should a set of run `Rule` objects be considered \"successful\"?\n\nIf `OR` then **any** triggered `Rule` object results in success.\n\nIf `AND` then **all** `Rule` objects must be triggered to result in success.",
"enum": [
"AND",
"OR"
],
"examples": [
"AND"
],
"type": "string"
},
"description": {
"examples": [
"A short description of what this check looks for and actions it performs"
],
"type": "string"
},
"dryRun": {
"description": "Use this option to override the `dryRun` setting for all of its `Actions`",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "Should this check be run by the bot?",
"examples": [
true
],
"type": "boolean"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of event (new submission or new comment) this check should be run against",
"enum": [
"submission"
],
"type": "string"
},
"name": {
"description": "Friendly name for this Check EX \"crosspostSpamCheck\"\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myNewCheck"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"notifyOnTrigger": {
"default": false,
"description": "If notifications are configured and this is `true` then an `eventActioned` event will be sent when this check is triggered.",
"type": "boolean"
},
"postFail": {
"anyOf": [
{
"$ref": "#/definitions/PostBehaviorOptionConfig"
},
{
"type": "string"
}
],
"default": "next",
"description": "Do this behavior if a Check is NOT triggered"
},
"postTrigger": {
"anyOf": [
{
"$ref": "#/definitions/PostBehaviorOptionConfig"
},
{
"type": "string"
}
],
"default": "nextRun",
"description": "Do this behavior if a Check is triggered"
},
"rules": {
"description": "A list of Rules to run.\n\nIf `Rule` objects are triggered based on `condition` then `actions` will be performed.\n\nCan be `Rule`, `RuleSet`, or the `name` of any **named** `Rule` in your subreddit's configuration.\n\n**If `rules` is an empty array or not present then `actions` are performed immediately.**",
"items": {
"anyOf": [
{
"$ref": "#/definitions/IncludesData"
},
{
"$ref": "#/definitions/RecentActivityRuleJSONConfig"
},
{
"$ref": "#/definitions/RepeatActivityJSONConfig"
},
{
"$ref": "#/definitions/AuthorRuleJSONConfig"
},
{
"$ref": "#/definitions/AttributionJSONConfig"
},
{
"$ref": "#/definitions/HistoryJSONConfig"
},
{
"$ref": "#/definitions/RegexRuleJSONConfig"
},
{
"$ref": "#/definitions/RepostRuleJSONConfig"
},
{
"$ref": "#/definitions/SentimentRuleJSONConfig"
},
{
"$ref": "#/definitions/MHSRuleJSONConfig"
},
{
"$ref": "#/definitions/RuleSetConfigData"
},
{
"type": "string"
}
]
},
"type": "array"
}
},
"required": [
"kind",
"name"
],
"type": "object"
},
"SubmissionState": {
"description": "Different attributes a `Submission` can be in. Only include a property if you want to check it.",
"examples": [
{
"over_18": true,
"removed": false
}
],
"properties": {
"age": {
"description": "A duration and how to compare it against a value\n\nThe syntax is `(< OR > OR <= OR >=) <number> <unit>` EX `> 100 days`, `<= 2 months`\n\n* EX `> 100 days` => Passes if the date being compared is before 100 days ago\n* EX `<= 2 months` => Passes if the date being compared is after or equal to 2 months\n\nUnit must be one of [DayJS Duration units](https://day.js.org/docs/en/durations/creating)\n\n[See] https://regexr.com/609n8 for example",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(days|weeks|months|years|hours|minutes|seconds|milliseconds)\\s*$",
"type": "string"
},
"approved": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"$ref": "#/definitions/ModeratorNameCriteria"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* true/false => test whether Activity is approved or not\n* string or list of strings => test which moderator approved this Activity"
},
"authorFlairBackgroundColor": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY color\n* If `false` then passes if NO color\n* If string or list of strings then color is matched, case-insensitive, without #. String may also be a regular expression enclosed in forward slashes."
},
"authorFlairCssClass": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY class\n* If `false` then passes if NO class\n* If string or list of strings then class is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"authorFlairTemplateId": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY flair\n* If `false` then passes if NO flair\n* If string or list of strings then template id is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"authorFlairText": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY flair\n* If `false` then passes if NO flair\n* If string or list of strings then text is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"createdOn": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "A relative datetime description to match the date the Activity was created\n\nMay be either:\n\n* day of the week (monday, tuesday, etc...)\n* cron expression IE `* * 15 *`\n\nSee https://crontab.guru/ for generating expressions\n\nhttps://regexr.com/6u3cc"
},
"deleted": {
"type": "boolean"
},
"dispatched": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "Test whether the activity is present in dispatched/delayed activities\n\nNOTE: This is DOES NOT mean that THIS activity is from dispatch -- just that it exists there. To test whether THIS activity is from dispatch use `source`\n\n* `true` => activity exists in delayed activities\n* `false` => activity DOES NOT exist in delayed activities\n* `string` => activity exists in delayed activities with given identifier\n* `string[]` => activity exists in delayed activities with any of the given identifiers"
},
"distinguished": {
"type": "boolean"
},
"filtered": {
"type": "boolean"
},
"flairTemplate": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if there is ANY flair template id\n* If `false` then passes if there is NO flair template id"
},
"isRedditMediaDomain": {
"description": "Is the submission a reddit-hosted image or video?",
"type": "boolean"
},
"is_self": {
"type": "boolean"
},
"link_flair_background_color": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if ANY color\n* If `false` then passes if NO color\n* If string or list of strings then color is matched, case-insensitive, without #. String may also be a regular expression enclosed in forward slashes."
},
"link_flair_css_class": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if flair has ANY css\n* If `false` then passes if flair has NO css\n* If string or list of strings then class is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"link_flair_text": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* If `true` then passes if flair has ANY text\n* If `false` then passes if flair has NO text\n* If string or list of strings then text is matched, case-insensitive. String may also be a regular expression enclosed in forward slashes."
},
"locked": {
"type": "boolean"
},
"over_18": {
"description": "NSFW",
"type": "boolean"
},
"pinned": {
"type": "boolean"
},
"removed": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"$ref": "#/definitions/ModeratorNameCriteria"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "* true/false => test whether Activity is removed or not\n* string or list of strings => test which moderator removed this Activity"
},
"reports": {
"description": "A string containing a comparison operator, a value to compare against, an (optional) report type filter, an (optional) qualifier for report reason, and an (optional) time constraint\n\nThe syntax is `(< OR > OR <= OR >=) number[%] [type] [reasonQualifier] [timeValue] [timeUnit]`\n\nIf only comparison and number is given then defaults to TOTAL reports on an Activity.\n\n* EX `> 2` => greater than 2 total reports\n\nType (optional) determines which type of reports to look at:\n\n* `mod` -- mod reports\n * EX `> 3 mod` => greater than 3 mod reports\n* `user` -- user reports\n * EX `> 3 user` => greater than 3 user reports\n\nReport reason qualifiers can be:\n\n* enclosed double or single quotes -- report reason contains\n * EX `> 1 \"misinformation\" => greater than 1 report with reason containing \"misinformation\"\n* enclosed in backslashes -- match regex\n * EX `> 1 \\harassment towards .*\\` => greater than 1 report with reason matching regex \\harassment towards .*\\\n\nType and reason qualifiers can be used together:\n\nEX `> 2 user \"misinformation\" => greater than 2 user reports with reasons containing \"misinformation\"\n\nThe time constraint filter reports created between NOW and [timeConstraint] in the past:\n\n* `> 3 in 30 minutes` => more than 3 reports created between NOW and 30 minutes ago\n* `> 2 user \"misinformation\" in 2 hours` => more than 2 user reports containing \"misinformation\" created between NOW and 2 hours ago",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)(\\s*%)?(\\s+(?:mods?|users?))?(\\s+(?:[\"'].*[\"']|\\/.*\\/))?.*(\\d+)?\\s*(days?|weeks?|months?|years?|hours?|minutes?|seconds?|milliseconds?)?\\s*$",
"type": "string"
},
"score": {
"description": "A string containing a comparison operator and a value to compare against\n\nThe syntax is `(< OR > OR <= OR >=) <number>`\n\n* EX `> 100` => greater than 100",
"pattern": "^\\s*(>|>=|<|<=)\\s*(\\d+)\\s*(%?)(.*)$",
"type": "string"
},
"source": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "Test where the current activity was sourced from.\n\nA source can be any of:\n\n* `poll` => activity was retrieved from polling a queue (unmoderated, modqueue, etc...)\n* `poll:[pollSource]` => activity was retrieved from specific polling source IE `poll:unmoderated` activity comes from unmoderated queue\n * valid sources: unmoderated modqueue newComm newSub\n* `dispatch` => activity is from Dispatch Action\n* `dispatch:[identifier]` => activity is from Dispatch Action with specific identifier\n* `user` => activity was from user input (web dashboard)"
},
"spam": {
"type": "boolean"
},
"spoiler": {
"type": "boolean"
},
"stickied": {
"type": "boolean"
},
"title": {
"description": "A valid regular expression to match against the title of the submission",
"type": "string"
},
"upvoteRatio": {
"description": "Compare the upvote ratio for this Submission, expressed as a whole number\n\nCan be either a comparison string or a number. If a number then CM assumes upvote ratio must be greater than or equal to this.\n\nExample:\n\n* `< 90` => less than 90% upvoted\n* 45 => greater than or equal to 45% upvoted",
"type": [
"string",
"number"
]
}
},
"type": "object"
},
"SubredditCriteria": {
"description": "Different attributes a `Subreddit` can be in. Only include a property if you want to check it.\n\nCan also set as plain string as a shorthand for `name: /subredditName/i`",
"examples": [
{
"over18": true
},
"mealtimevideos"
],
"properties": {
"isOwnProfile": {
"description": "Test whether the subreddit is the profile of the Author of the Activity being checked",
"type": "boolean"
},
"isUserProfile": {
"description": "Test whether the subreddit is a user profile",
"type": "boolean"
},
"name": {
"anyOf": [
{
"$ref": "#/definitions/RegExp"
},
{
"type": "string"
}
],
"description": "The name of the subreddit.\n\nCan be a normal string (will check case-insensitive) or a regular expression\n\nEX `[\"mealtimevideos\", \"/onlyfans*\\/i\"]`",
"examples": [
"mealtimevideos",
"/onlyfans*/i"
]
},
"over18": {
"description": "Is subreddit NSFW/over 18?\n\n**Note**: This is **mod-controlled flag** so it is up to the mods of the subreddit to correctly mark their subreddit as NSFW",
"type": "boolean"
},
"quarantine": {
"description": "Is subreddit quarantined?",
"type": "boolean"
},
"stateDescription": {
"description": "A friendly description of what this State is trying to parse",
"type": "string"
}
},
"type": "object"
},
"ThirdPartyCredentialsJsonConfig": {
"additionalProperties": {},
"properties": {
"mhs": {
"properties": {
"apiKey": {
"type": "string"
}
},
"required": [
"apiKey"
],
"type": "object"
},
"youtube": {
"properties": {
"apiKey": {
"type": "string"
}
},
"required": [
"apiKey"
],
"type": "object"
}
},
"type": "object"
},
"TimeBasedSelector": {
"enum": [
"all",
"any",
"newest",
"oldest"
],
"type": "string"
},
"UserFlairActionJson": {
"description": "Flair the Submission",
"properties": {
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"css": {
"description": "The text of the css class of the flair to apply",
"type": "string"
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"flair_template_id": {
"description": "Flair template to pick.\n\n**Note:** If this template is used text/css are ignored",
"type": "string"
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"userflair"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"text": {
"description": "The text of the flair to apply",
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"UserNoteActionJson": {
"description": "Add a Toolbox User Note to the Author of this Activity",
"properties": {
"allowDuplicate": {
"default": false,
"description": "Add Note even if a Note already exists for this Activity\n\nUSE `existingNoteCheck` INSTEAD",
"examples": [
false
],
"type": "boolean"
},
"authorIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/AuthorCriteria"
},
{
"$ref": "#/definitions/NamedCriteria<AuthorCriteria>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<AuthorCriteria>"
}
],
"description": "If present then these Author criteria are checked before running the Check. If criteria fails then the Check will fail."
},
"content": {
"description": "The Content to submit for this Action. Content is interpreted as reddit-flavored Markdown.\n\nIf value starts with `wiki:` then the proceeding value will be used to get a wiki page from the current subreddit\n\n * EX `wiki:botconfig/mybot` tries to get `https://reddit.com/r/currentSubreddit/wiki/botconfig/mybot`\n\nIf the value starts with `wiki:` and ends with `|someValue` then `someValue` will be used as the base subreddit for the wiki page\n\n* EX `wiki:replytemplates/test|ContextModBot` tries to get `https://reddit.com/r/ContextModBot/wiki/replytemplates/test`\n\nIf the value starts with `url:` then the value is fetched as an external url and expects raw text returned\n\n* EX `url:https://pastebin.com/raw/38qfL7mL` tries to get the text response of `https://pastebin.com/raw/38qfL7mL`\n\nIf none of the above is used the value is treated as the raw context\n\n * EX `this is **bold** markdown text` => \"this is **bold** markdown text\"\n\nAll Content is rendered using [mustache](https://github.com/janl/mustache.js/#templates) to enable [Action Templating](https://github.com/FoxxMD/context-mod#action-templating).\n\nThe following properties are always available in the template (view individual Rules to see rule-specific template data):\n```\nitem.kind => The type of Activity that was checked (comment/submission)\nitem.author => The name of the Author of the Activity EX FoxxMD\nitem.permalink => A permalink URL to the Activity EX https://reddit.com/r/yourSub/comments/o1h0i0/title_name/1v3b7x\nitem.url => If the Activity is Link Sumbission then the external URL\nitem.title => If the Activity is a Submission then the title of that Submission\nrules => An object containing RuleResults of all the rules run for this check. See Action Templating for more details on naming\n```",
"examples": [
"This is the content of a comment/report/usernote",
"this is **bold** markdown text",
"wiki:botconfig/acomment"
],
"type": "string"
},
"dryRun": {
"default": false,
"description": "If `true` the Action will not make the API request to Reddit to perform its action.",
"examples": [
false,
true
],
"type": "boolean"
},
"enable": {
"default": true,
"description": "If set to `false` the Action will not be run",
"examples": [
true
],
"type": "boolean"
},
"existingNoteCheck": {
"anyOf": [
{
"$ref": "#/definitions/UserNoteCriteria"
},
{
"type": "boolean"
}
],
"default": true,
"description": "Check if there is an existing Note matching some criteria before adding the Note.\n\nIf this check passes then the Note is added. The value may be a boolean or UserNoteCriteria.\n\nBoolean convenience:\n\n* If `true` or undefined then CM generates a UserNoteCriteria that passes only if there is NO existing note matching note criteria\n* If `false` then no check is performed and Note is always added",
"examples": [
true
]
},
"itemIs": {
"anyOf": [
{
"items": {
"anyOf": [
{
"$ref": "#/definitions/SubmissionState"
},
{
"$ref": "#/definitions/CommentState"
},
{
"$ref": "#/definitions/NamedCriteria<TypedActivityState>"
},
{
"type": "string"
}
]
},
"type": "array"
},
{
"$ref": "#/definitions/FilterOptionsJson<TypedActivityState>"
}
],
"description": "A list of criteria to test the state of the `Activity` against before running the check.\n\nIf any set of criteria passes the Check will be run. If the criteria fails then the Check will fail.\n\n* @examples [[{\"over_18\": true, \"removed': false}]]"
},
"kind": {
"description": "The type of action that will be performed",
"enum": [
"usernote"
],
"type": "string"
},
"name": {
"description": "An optional, but highly recommended, friendly name for this Action. If not present will default to `kind`.\n\nCan only contain letters, numbers, underscore, spaces, and dashes",
"examples": [
"myDescriptiveAction"
],
"pattern": "^[a-zA-Z]([\\w -]*[\\w])?$",
"type": "string"
},
"type": {
"description": "User Note type key",
"examples": [
"spamwarn"
],
"type": "string"
}
},
"required": [
"kind",
"type"
],
"type": "object"
},
"UserNoteCriteria": {
"properties": {
"count": {
"default": ">= 1",
"description": "Number of occurrences of this type. Ignored if `search` is `current`\n\nA string containing a comparison operator and/or a value to compare number of occurrences against\n\nThe syntax is `(< OR > OR <= OR >=) <number>[percent sign] [in timeRange] [ascending|descending]`\n\nIf `timeRange` is given then only notes/mod actions that occur between timeRange and NOW will be returned. `timeRange` is ignored if search is `current`",
"examples": [
">= 1"
],
"pattern": "^\\s*(?<opStr>>|>=|<|<=)\\s*(?<value>\\d+)\\s*(?<percent>%?)\\s*(?<duration>in\\s+\\d+\\s*(days?|weeks?|months?|years?|hours?|minutes?|seconds?|milliseconds?))?\\s*(?<extra>asc.*|desc.*)*$",
"type": "string"
},
"note": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "The content of the Note to search For.\n\n* Can be a single string or list of strings to search for. Each string will be searched for case-insensitive, as a subset of note content.\n* Can also be Regular Expression if wrapped in forward slashes IE '\\/test.*\\/i'"
},
"referencesCurrentActivity": {
"type": "boolean"
},
"search": {
"default": "current",
"description": "How to test the Toolbox Notes or Mod Actions for this Author:\n\n### current\n\nOnly the most recent note is checked for criteria\n\n### total\n\n`count` comparison of mod actions/notes must be found within all history\n\n* EX `count: > 3` => Must have more than 3 notes of `type`, total\n* EX `count: <= 25%` => Must have 25% or less of notes of `type`, total\n* EX: `count: > 3 in 1 week` => Must have more than 3 notes within the last week\n\n### consecutive\n\nThe `count` **number** of mod actions/notes must be found in a row.\n\nYou may also specify the time-based order in which to search the notes by specifying `ascending (asc)` or `descending (desc)` in the `count` value. Default is `descending`\n\n* EX `count: >= 3` => Must have 3 or more notes of `type` consecutively, in descending order\n* EX `count: < 2` => Must have less than 2 notes of `type` consecutively, in descending order\n* EX `count: > 4 asc` => Must have greater than 4 notes of `type` consecutively, in ascending order",
"enum": [
"consecutive",
"current",
"total"
],
"examples": [
"current"
],
"type": "string"
},
"type": {
"description": "User Note type key to search for",
"examples": [
"spamwarn"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
"UserResultCacheOptions": {
"description": "Cache the result of this check based on the comment author and the submission id\n\nThis is useful in this type of scenario:\n\n1. This check is configured to run on comments for specific submissions with high volume activity\n2. The rules being run are not dependent on the content of the comment\n3. The rule results are not likely to change while cache is valid",
"properties": {
"enable": {
"default": false,
"type": "boolean"
},
"runActions": {
"default": true,
"description": "In the event the cache returns a triggered result should the actions for the check also be run?",
"type": "boolean"
},
"ttl": {
"default": 60,
"description": "The amount of time, in seconds, to cache this result",
"examples": [
60
],
"type": "number"
}
},
"type": "object"
}
},
"properties": {
"caching": {
"$ref": "#/definitions/CacheConfig",
"description": "Per-subreddit config for caching TTL values. If set to `false` caching is disabled."
},
"checks": {
"description": "A list of all the checks that should be run for a subreddit.\n\nChecks are split into two lists -- submission or comment -- based on kind and run independently.\n\nChecks in each list are run in the order found in the configuration.\n\nWhen a check \"passes\", and actions are performed, then all subsequent checks are skipped.",
"items": {
"anyOf": [
{
"$ref": "#/definitions/IncludesData"
},
{
"$ref": "#/definitions/SubmissionCheckConfigData"
},
{
"$ref": "#/definitions/CommentCheckConfigData"
},
{
"type": "string"
}
]
},
"minItems": 1,
"type": "array"
},
"credentials": {
"$ref": "#/definitions/ThirdPartyCredentialsJsonConfig"
},
"databaseStatistics": {
"$ref": "#/definitions/DatabaseStatisticsJsonConfig"
},
"dryRun": {
"default": "undefined",
"description": "Use this option to override the `dryRun` setting for all `Checks`",
"examples": [
false,
true
],
"type": "boolean"
},
"filterCriteriaDefaults": {
"$ref": "#/definitions/FilterCriteriaDefaultsJson",
"description": "Set the default filter criteria for all checks. If this property is specified it will override any defaults passed from the bot's config\n\nDefault behavior is to exclude all mods and automoderator from checks"
},
"footer": {
"anyOf": [
{
"enum": [
false
],
"type": "boolean"
},
{
"type": "string"
}
],
"default": "undefined",
"description": "Customize the footer for Actions that send replies (Comment/Ban). **This sets the default value for all Actions without `footer` specified in their configuration.**\n\nIf `false` no footer is appended\n\nIf `string` the value is rendered as markdown or will use `wiki:` parser the same way `content` properties on Actions are rendered with [templating](https://github.com/FoxxMD/context-mod#action-templating).\n\nIf footer is `undefined` (not set) the default footer will be used:\n\n> *****\n> This action was performed by [a bot.] Mention a moderator or [send a modmail] if you any ideas, questions, or concerns about this action.\n\n*****\n\nThe following properties are available for [templating](https://github.com/FoxxMD/context-mod#action-templating):\n```\nsubName => name of subreddit Action was performed in (EX 'mealtimevideos')\npermaLink => The permalink for the Activity the Action was performed on EX https://reddit.com/r/yourSub/comments/o1h0i0/title_name/1v3b7x\nmodmaiLink => An encoded URL that will open a new message to your subreddit with the Action permalink appended to the body\nbotLink => A permalink to the FAQ for this bot.\n```\nIf you use your own footer or no footer **please link back to the bot FAQ** using the `{{botLink}}` property in your content :)"
},
"nickname": {
"type": "string"
},
"notifications": {
"$ref": "#/definitions/NotificationConfig"
},
"polling": {
"default": [
[
"unmoderated"
]
],
"description": "An array of sources to process Activities from\n\nValues in the array may be either:\n\n**A `string` representing the `pollOn` value to use**\n\nOne of:\n\n* `unmoderated`\n* `modqueue`\n* `newSub`\n* `newComm`\n\nwith the rest of the `PollingOptions` properties as defaults\n\n**A `PollingOptions` object**\n\nIf you want to specify non-default properties\n\n****\nIf not specified the default is `[\"unmoderated\"]`",
"items": {
"anyOf": [
{
"$ref": "#/definitions/PollingOptions"
},
{
"type": "string"
}
]
},
"type": "array"
},
"postCheckBehaviorDefaults": {
"$ref": "#/definitions/PostBehavior",
"description": "Set the default post-check behavior for all checks. If this property is specified it will override any defaults passed from the bot's config\n\nDefault behavior is:\n\n* postFail => next\n* postTrigger => nextRun"
},
"queue": {
"properties": {
"maxWorkers": {
"default": 1,
"description": "The maximum number of events that can be processed simultaneously.\n\n**Do not modify this setting unless you know what you are doing.** The default of `1` is suitable for the majority of use-cases.\n\nRaising the max above `1` could be useful if you require very fast response time to short bursts of high-volume events. However logs may become unreadable as many events are processed at the same time. Additionally, any events that depend on past actions from your bot may not be processed correctly given the concurrent nature of this use case.\n\n**Note:** Max workers are also enforced at the operator level so a subreddit cannot raise their max above what is specified by the operator.",
"examples": [
1
],
"minimum": 1,
"type": "number"
}
},
"type": "object"
},
"retention": {
"anyOf": [
{
"$ref": "#/definitions/DurationObject"
},
{
"type": [
"string",
"number"
]
}
],
"description": "Number of Events, or time range of events were processed during, that should continue to be stored in the database.\n\nAny Events falling outside this criteria will be deleted\n\nLeave unspecified to disable deleting anything"
},
"runs": {
"description": "A list of sets of Checks to run",
"items": {
"anyOf": [
{
"$ref": "#/definitions/IncludesData"
},
{
"$ref": "#/definitions/RunConfigData"
},
{
"type": "string"
}
]
},
"minItems": 1,
"type": "array"
},
"sharing": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"$ref": "#/definitions/SharingACLConfig"
},
{
"type": "boolean"
}
],
"description": "Enables config sharing\n\n* (Default) When `false` sharing is not enabled\n* When `true` any bot that can access this bot's config wiki page can use inpm t\n* When an object, use `include` or `exclude` to define subreddits that can access this config"
}
},
"type": "object"
}