Compare commits

..

137 Commits

Author SHA1 Message Date
FoxxMD
eee2a8e856 feat: Support multiple expressions for regex property 2022-11-22 16:03:50 -05:00
FoxxMD
e79779d980 feat: Implement templating for flair actions 2022-11-21 11:43:34 -05:00
FoxxMD
b094b72d4a docs: Update docker compose instructions
* Specify docker-compose minimum version
* Change commands to use new syntax
2022-11-21 11:29:14 -05:00
FoxxMD
d90e88360d feat: Add some author properties for templating 2022-11-17 13:16:10 -05:00
FoxxMD
9031f7fec8 refactor(polling): Improve resilience for polling source parsing
* Replace hard-coded polling sources with string constants
* Implement string to PollOn parsing which is case-insensitive and forgives mispelling
* Check that manager specifies only one of each polling source type when build config
2022-11-17 12:03:55 -05:00
FoxxMD
0a2b13e4c4 fix: Fix including self activities in Recent Activity without filtering
* Consolidate ACID check for author history results into authorActivities function so it can be used everywhere
* Remove self check in Recent Activity and used consolidated functionality so that filtering still occurs on current activity
2022-11-16 10:18:37 -05:00
FoxxMD
5183747219 feat(docs): Improve jekyll dependencies to speed up docker image build 2022-11-15 13:58:35 -05:00
FoxxMD
718f81b921 feat(docs): Generate docs on startup or in docker build
* Generate docs if none found on Web client startup
* Add "Docs" link to local docs index
* Add working implementation of building docs in docker image
2022-11-15 13:07:40 -05:00
FoxxMD
154603328c chore: Exclude jekyll generated files from typescript compiler 2022-11-15 10:15:16 -05:00
FoxxMD
4041ea5bb5 docs: Revert to using docs folder only
* Using project dir copies too much to _site directory and causes TS issues
* In order to keep "home" page in generated docs need to duplicate project README (unfortunately)
2022-11-15 09:36:29 -05:00
FoxxMD
981591a5fa docs: Add more filters documentation 2022-11-14 14:42:56 -05:00
FoxxMD
999329c6ce docs: Add missing mermaid version 2022-11-14 13:28:44 -05:00
FoxxMD
d7cf15dcc1 docs: Fix links in main readme 2022-11-14 12:21:57 -05:00
FoxxMD
f58430c615 docs: Add doc site development documentation 2022-11-14 11:59:02 -05:00
FoxxMD
8e18afbda9 chore: Add excluded folders for idea 2022-11-14 11:54:23 -05:00
FoxxMD
b3b0d92f2a docs: Use project README as index and fix more links 2022-11-14 11:54:07 -05:00
FoxxMD
34ee5da082 docs: Fix broken link 2022-11-14 11:33:05 -05:00
FoxxMD
ba8ad100bc docs: Fix detail expansion blocks
https://github.com/just-the-docs/just-the-docs/issues/246#issuecomment-643783307
2022-11-14 10:46:40 -05:00
FoxxMD
4b6f66499a docs: Fix relative links 2022-11-09 15:19:47 -05:00
FoxxMD
9a08df1990 testing relative links in plain docs with parent 2022-11-09 14:47:03 -05:00
FoxxMD
1f3aa8e732 testing relative links in plain docs 2022-11-09 14:44:53 -05:00
FoxxMD
ec98d8f629 docs: Initial implementation of just-the-docs 2022-11-09 14:22:53 -05:00
FoxxMD
2d8b7f7b86 fix: Modify reddit entity parsing regex to allow subreddit names that have been replaced with placeholders
Placeholder naming broke "normal" subreddit naming convention
2022-11-08 09:47:20 -05:00
FoxxMD
b9f85814d4 Merge branch 'dockerCompose' into edge 2022-11-01 16:41:14 -04:00
FoxxMD
e11a1d2a52 feat: Add full docker-compose support and documentation
* Annotated docker-compose file
* simplified CM config.yaml for docker-compose "base"
* instructions for usage in installation docs
2022-11-01 16:41:00 -04:00
FoxxMD
43bfa3ca51 fix(ui): Add workaround for removal reason copy-to-clipboard when in unsecure context 2022-10-31 11:30:17 -04:00
FoxxMD
0127cbfd0f docs: Add cookbook recipe for monitoring popular submissions 2022-10-27 15:40:53 -04:00
FoxxMD
59d31bde84 feat(comment): Implement commenting as subreddit 2022-10-27 14:29:05 -04:00
FoxxMD
17ae7fa295 refactor(modnotes): Encapsulate filtering functionality in modnote class for future testing 2022-10-27 11:36:12 -04:00
FoxxMD
bf074487ff fix: Fix how submission/comment snoowrap entities are generated from reddit thing ids 2022-10-27 11:34:12 -04:00
FoxxMD
85e786d248 fix(filter): Re-add missing modaction filtering improvements
They were removed by a merge somewhere??
2022-10-27 09:56:45 -04:00
FoxxMD
641a7fbd63 fix(filter): Fix usernote cutoff date comparison 2022-10-27 09:50:05 -04:00
FoxxMD
0278a4d673 feat(filter): Improve building filters from config
* Fix ignoring of filters when they are plain objects
* Fix default filter merging behavior to account for "new" filter structure (named criteria)
* Add tests for building/merging filters
2022-10-26 14:43:44 -04:00
FoxxMD
d318286507 fix(cache): Fix more memory provider cache object reconstruction issues #123
Same issues as a949a4ed10 -- memory provider stores objects in memory (no serialization) so need to check for object instance before trying to reconstruct
2022-10-26 09:48:41 -04:00
FoxxMD
36221705fa fix(filter): Fix filtered usernote assignment when search type is current and no notes exist
Addresses #123
2022-10-26 09:27:15 -04:00
FoxxMD
fdc0ccf4c8 fix(mhs): Fix examples missing criteria property 2022-10-25 16:51:47 -04:00
FoxxMD
a949a4ed10 fix(cache): Fix pre activities being wrongly reconstructed when retrieved from memory provider cache
Thanks @CryptoMaximalist for reporting the bug and providing logs!
2022-10-25 15:32:47 -04:00
FoxxMD
d67283a923 feat(filter): Add same regex/matching functionality for author flair filtering as item has 2022-10-24 13:02:27 -04:00
FoxxMD
21b2182ef0 fix(filter): Re-add missing item is criteria to filter test
Somehow got removed during refactor! Oops
2022-10-24 11:51:47 -04:00
FoxxMD
fcfb037d6c feat(docs): Add more cookbook recipies 2022-10-20 12:33:20 -04:00
FoxxMD
8c3601a4cf refactor(docs): Improve CM examples by using a "cookbook"
* Better instructions on how to use configs
* Remove json examples since everything else in docs is yaml
2022-10-20 10:49:17 -04:00
FoxxMD
cfc96b6c82 Merge branch 'sharedBaseConfig' into edge
# Conflicts:
#	src/Subreddit/UserNotes.ts
2022-10-20 09:37:01 -04:00
FoxxMD
239d173ffd feat(config): Implement ACL for full config sharing 2022-10-20 09:35:26 -04:00
FoxxMD
fda6090ddd feat(config): Refactor manager config updates to check hydrated structure
Instead of checking wiki revision, check hydrated (with config fragments) config hash against last good config hash
2022-10-19 16:19:39 -04:00
FoxxMD
d23f87ba60 feat(config): Add config fragments to shared cache 2022-10-19 16:19:29 -04:00
FoxxMD
2941386955 feat(cache): Add force/shared options for getting content/wiki/url results from subreddit resources
* Also refactor Manager to use subreddit resources for getting wiki page (DRY)
2022-10-19 15:15:58 -04:00
FoxxMD
b2b924c01d feat(cache): Add default prefix and shared option for interacting with cache
Enables getting cache KVs from shared *always* based on logic flow
2022-10-19 15:15:01 -04:00
FoxxMD
ee20ba786b refactor: Move cache key prefix into CMCache
* Makes adding prefix cache provider agnostic
* Prepares for #115
2022-10-19 14:33:05 -04:00
FoxxMD
f71933b9b9 refactor: Improve reuseability of SubredditResources
* Extract cache related functions into own class and encapsulate pruning/key search there as well
* Refactor SubredditStates to be "re-init"-able if state frequency changes
* Simplify and SubredditSource init and configuration functionality so that class is only created once and then reconfigured if major settings change
  * Only reinstantiates stats or cache class based on setting changes
* Remove obsolete maxActionedEvents from operator/subreddit config (from pre-db code)
2022-10-19 14:13:23 -04:00
FoxxMD
e6246188ad refactor: Extract stat-related functionality from SubredditResources into its own class 2022-10-19 11:23:24 -04:00
FoxxMD
bfd5ba7816 refactor: Consolidate ttl values into well-defined object 2022-10-19 10:02:44 -04:00
FoxxMD
fd5488376a docs: Add template variable examples for most rules #121 2022-10-18 13:18:12 -04:00
FoxxMD
6c8ea66fcc docs: Typo fix 2022-10-18 11:07:19 -04:00
FoxxMD
acbb9a8626 feat(usernote): Improve usernote filtering functionality
Same as modActions...

* Add `referencesCurrentActivity` boolean to filter by notes associated with current activity
* Add `note` string property to filter by note content (string or regular expression)
* Replace `allowDuplicates` with `existingNoteCheck` on UserNoteAction to allow for more granular note control on action
2022-10-17 15:32:47 -04:00
FoxxMD
122d5fb2af docs: Fix malformed URLs
Fixes #114
2022-10-17 14:16:34 -04:00
FoxxMD
cd8ccffa20 feat(config): Enable pulling run fragments from root subreddit config
* Refactor config fragment validation into parsing function
* Check for `runs` in config fragment
2022-10-17 13:52:12 -04:00
FoxxMD
8695058064 refactor: Seperate subreddit resources from bot resource manager 2022-10-17 13:52:09 -04:00
FoxxMD
1271eee4c5 Improvements 2022-10-14 11:18:33 -04:00
FoxxMD
98a8568eb6 fix: Add missing else condition 2022-10-13 16:17:43 -04:00
FoxxMD
457f947603 fix: Further improvements for influxdb logging
* Suppress write failure warnings to reduce noise in log
  * Can be toggled using debug flag in config
2022-10-13 12:34:11 -04:00
FoxxMD
7fb69ae67a fix: Attempt to decrease frequency of influxdb timeout errors
* Use keep-alive http agent to reuse open connections
* Decrease max batch size and flush interval to payload sent is smaller
* Add debug logging for fail/success/retry events on flush
2022-10-13 11:39:45 -04:00
FoxxMD
2241d40e49 fix: Fix custom footer never loading
Custom footer needs to be loaded AFTER resources are set
2022-10-13 08:58:12 -04:00
FoxxMD
a3ca3f17ec refactor(recent): Log image parsing error with cause 2022-10-12 14:39:21 -04:00
FoxxMD
f527a17fa2 feat(modnote): Implement existing note check before adding note to replace allowDuplicates
* Use "modActions" authorIs filtering to check note prior to adding note using "existingNoteCheck" property
  * Refactors concept of "allowDuplicates" to allow any arbitrary modActions test to be used
* Provide convenience ModLogCriteria generation for "existingNoteCheck" based on boolean (emulates allowDuplicates functionality)
2022-10-12 13:00:47 -04:00
FoxxMD
e98364eae9 feat(filter): Improve modAction filtering functionality
* Implement filtering activityType by "false" in order to return actions/notes not added to a specific activity
* Implement "referencesCurrentActivity" property to allow filtering by actions/notes that are associated with the activity being processed
* Implement using "count" for "current" search to enable criteria condition based on presence or non-presence of current action/note passing
2022-10-12 12:58:49 -04:00
FoxxMD
8b125d7433 feat(ui): Improve visibility and resilience for live log stream
* Tie loading indicator to live stream status and display error if one occurs
  * Add manual restart action to end of error
* Restart stream automatically if reader ends, up to 3 retries
2022-10-11 12:19:55 -04:00
FoxxMD
6ee060c5ce fix(logs): Remove listeners from log stream event emitter before end of response to prevent write-after-end errors 2022-10-11 12:18:00 -04:00
FoxxMD
9b12d0b2b3 feat(bot): Improve log wording for manager loading phase 2022-10-11 10:51:00 -04:00
FoxxMD
b174c7928a feat(ui): Add favicon files 2022-10-11 10:49:57 -04:00
FoxxMD
59f935ce46 Barebones docker-compose 2022-10-11 09:56:08 -04:00
FoxxMD
74dfe9258a fix(filter): Fix mod action note filtering assignment 2022-10-10 15:00:39 -04:00
FoxxMD
1cf8855a24 feat(testing): Implement initial author filter tests 2022-10-10 12:06:08 -04:00
FoxxMD
adc69894fc fix(filter): Fix detecting empty filter when using 'replace' filter default behavior 2022-10-10 11:03:57 -04:00
FoxxMD
3435c683c8 feat(filter): Add author flair item criteria 2022-10-05 11:24:44 -04:00
FoxxMD
f0032cd433 Bump version 2022-10-05 08:56:53 -04:00
FoxxMD
ade0b7948e Add patreon funding link 2022-10-04 09:40:03 -04:00
FoxxMD
542aa26c62 feat(history): Implement ratio comparison #112 2022-10-03 13:25:05 -04:00
FoxxMD
3faf4ca3dc fix: Fix wiki location usage when getting from subreddit resources 2022-09-28 10:34:48 -04:00
FoxxMD
2f35b82d5e feat(history): Log failure results for easier rule tuning 2022-09-28 10:25:26 -04:00
FoxxMD
c9d8bf637b chore: Add tests for item criteria 2022-09-26 16:59:46 -04:00
FoxxMD
027f4087e3 refactor: Improve activity source parse and comparison
* Implement a DTO class for activity source to make parts usage (type, identifier) and matching easier
* Implement regex to parse type and identifier from activity source string
* Refactor activity source interface/types to better distinguish as string, data, and class
2022-09-26 12:07:24 -04:00
FoxxMD
1b20122ffc docs: Fix some typos 2022-09-23 10:35:13 -04:00
FoxxMD
5d53571ec0 fix: Fix typo in default footer
Thanks u/SampleOfNone for catching that
2022-09-22 10:59:57 -04:00
FoxxMD
b3df1b4d41 Update default confidence for MHS based on feedback from Welton 2022-09-20 10:56:39 -04:00
FoxxMD
4abe8e07f3 docs: Add docs for MHS toxic content prediction rule 2022-09-20 10:44:08 -04:00
FoxxMD
9bb95106ba feat(mhs): Add default confidence threshold 2022-09-20 09:35:38 -04:00
FoxxMD
02414478bf feat: Implement rule that tests activity content against moderatehatespeech.com ML model using api #110
* Add mhs rule type and MHS credentials interface
* Implement MHS rule with similar criteria options to sentiment
* Allow testing against author history content
2022-09-19 16:20:35 -04:00
FoxxMD
8b0a582464 fix(recent): Empty viable activity list if processing activity is required to be reference but is not a valid type 2022-09-19 11:46:20 -04:00
FoxxMD
d1db5f4688 fix: Fix subreddit filtering result when no subreddit criteria are present
Should return all items instead of none. Thanks u/SampleOfNone for helping track this down with examples.
2022-09-19 10:01:39 -04:00
FoxxMD
44f9389b69 docs: Add general subreddit/moderator docs readme
* Also add Guest Access docs
2022-09-16 16:40:28 -04:00
FoxxMD
71b2d0597d docs: Update screenshots 2022-09-16 15:38:52 -04:00
FoxxMD
57cfcebe9f fix: Set default invites to empty array on heartbeat 2022-09-16 14:34:28 -04:00
FoxxMD
07ecc505ff fix: Check bot entity exists before getting invites 2022-09-16 14:29:34 -04:00
FoxxMD
81213686ce Merge branch 'subredditInviteUI' into edge
# Conflicts:
#	src/Subreddit/SubredditResources.ts
2022-09-16 13:31:37 -04:00
FoxxMD
08735d505a refactor(manager): Improve wiki CRUD and onboarding initial config
* Refactor write/read into separate functions
* Improve error hinting for wiki read/write/permissions WRT mod/oauth permissions
* Remove superfluous error wrapping to reduce logging length for wiki errors
* More debug logging for onboarding process
* Don't return error if manager fails to parse after all onboarding complete (not critical)
2022-09-16 13:27:41 -04:00
FoxxMD
1a62c752c1 feat(ui): Improve finished onboarding response
* don't redirect on error
* increase delay to redirect on success
2022-09-16 13:24:09 -04:00
FoxxMD
6aa7367297 fix(client): Improve responses dependent on server information
* run initHeartbeat on any GET route that render a page so that user doesn't get access denied on initial app load
* Force client refresh if no invite found on initial check for onboarding landing
2022-09-16 13:22:44 -04:00
FoxxMD
cf9583227c feat: Add subredditExists function to snoowrap client
Reddit returns 403 if the subreddit exists but is private. Using this function wraps the error so we can just get boolean back along with subreddit object, if successful
2022-09-16 13:20:07 -04:00
FoxxMD
aa505ba3f2 feat: Improve external resource fetching in subreddit resources
* Add "default" hint to force val to a url or wiki key if neither is detected but know it should be one of them
* Refactor wiki/url fetching into own functions for better reuseability
* Implement mod permission getter function to check for valid permissions on wiki page error
* Improve error hints on wiki page read failure
2022-09-16 13:19:23 -04:00
FoxxMD
a0182d89ca feat: util function for generating full wiki urls 2022-09-16 13:16:26 -04:00
FoxxMD
d46f0a5be8 fix: Improve error detection for log transform
Check for error name OR stack existence
2022-09-16 13:16:06 -04:00
FoxxMD
4a55d35e14 feat(filter): Rename createdAt to createdOn
Better naming
2022-09-15 13:27:41 -04:00
FoxxMD
1284051fe8 fix(filter): Fix copy-past typo for createdAt 2022-09-15 11:24:53 -04:00
FoxxMD
00680494a3 feat(filter): Add createdAt activity criteria matching
* May be a string or array of strings. Passes if any expression matches
  * Value may be a convience day-of-week value (mon, tues, wed...)
  * or a cron expression
2022-09-15 11:22:04 -04:00
FoxxMD
77856a6d97 chore: Bump version 2022-09-14 15:30:12 -04:00
FoxxMD
b216cd08e1 Merge branch 'edge' into subredditInviteUI 2022-09-14 15:27:14 -04:00
FoxxMD
052c1218c6 feat(ui): Add home logo 2022-09-14 15:26:59 -04:00
FoxxMD
c2343683bb Finish implementation accept flow 2022-09-14 15:12:33 -04:00
FoxxMD
fcf718f1d0 fix(ui): Fix typo in reddit status indicator switch 2022-09-14 13:21:48 -04:00
FoxxMD
77f848007a Implement subreddit onboarding accept process
* Refactor some manager/bot methods to be more accessible for invites/wiki
* Add routes and authentication for getting invite information and checking user is moderator of subreddit
* Add route for accept invite and completing onboarding guest/config
2022-09-14 13:20:53 -04:00
FoxxMD
95216b3950 docs: Add GHCR image location to install docs
Closes #109
2022-09-13 15:06:13 -04:00
FoxxMD
58a21e8d05 Scope required permissions for github token 2022-09-13 14:35:11 -04:00
FoxxMD
49ac8cda19 feat: Update github actions to push to multiple registries
And add documentation for GH actions local dev/testing
2022-09-13 14:23:22 -04:00
FoxxMD
bc8be3608b Use methods for bot entity subreddit invite crud 2022-09-13 10:33:55 -04:00
FoxxMD
1b69cd78bb Refactor subreddit invites to use db and add interface
* Refactor to use db instead of cache for persisting invites
* Implement subreddit invite helper page
* Add initial config and guests as optional data for invite
* Refactor bot to use db subreddit invite and auto-accept when no config/guests

TODO: subreddit accept page, mod authorization, initial config usage, and documentation
2022-09-12 16:29:41 -04:00
FoxxMD
e736379f85 feat(ui): Improve guest expiration interface
* Set default time to 24 hours
* Add label and tooltip for expiration datetime picker
2022-09-07 11:57:29 -04:00
FoxxMD
c0e1a93fb4 fix(config): Use correct filter defaults data structure for runs
Should use "json" data structure type so named filters can be used in defaults on runs
2022-09-06 11:18:24 -04:00
FoxxMD
bd35b06ebf fix(filter): Fix missed toLowerCase for named filter getter 2022-09-02 17:41:28 -04:00
FoxxMD
f852e85234 feat(author): authorIs 'name' criteria may be regular expression 2022-09-02 16:21:53 -04:00
FoxxMD
661ae11e18 refactor(ui): Replace websockets opStats with client delta polling #106
* Refactor/remove websockets functionality for relaying opstats from server with direct polling by client
* Implement delta responses initially introduced in #91 to reduce bandwidth
2022-09-01 16:01:37 -04:00
FoxxMD
18c1ac0fd7 Chore: Bump version 2022-09-01 09:03:12 -04:00
FoxxMD
2fb503f09f feat(message): Implement templating for to field so subreddit can be used generically
since 'to' be now be templated a user can configure a message to send to the subreddit the action is being processed from using `to: 'r/{{item.subreddit}}'`
2022-08-31 09:58:24 -04:00
FoxxMD
7e5eeb71da fix(submission): Fix targets data type to accept array 2022-08-31 09:31:25 -04:00
FoxxMD
84f2da8b6d feat(action): Implement Action templating data #104
* Add top-level 'actionSummary' template variable that renders a markdown list of action results
* Add individual action result/data, in the same structure as rules, under the top-level 'actions' template variable
2022-08-30 17:12:51 -04:00
FoxxMD
be51f8ae43 fix(image): Fix hash result test assertion 2022-08-30 16:13:35 -04:00
FoxxMD
f82d985eab feat(template): Refactor templating to be more extensible and add some requested data
* Implement interfaces for template parts
* Refactor Action constructor to take an object for runtime options (cleaner, more extensible)
* Refactor subreddit resource and snoowraputils content rendering and organization to use objects of optional data rather than required arguments
  * Make almost all data optional and only parse/render if included
  * Move rule results parsing/formatting into own function
  * Refactor footer render to use renderContent (DRY)
* Add some requested template data #104
  * {{item.subreddit}} #87
  * {{check}} #87
* Updated templating documentation
2022-08-26 13:42:02 -04:00
FoxxMD
aab014650a fix(template): Fix rule data spread to template 2022-08-26 11:22:59 -04:00
FoxxMD
113ac3e10e fix(template): Fix subreddit breakdown reference override 2022-08-25 17:14:28 -04:00
FoxxMD
afb6aad26d fix(template): Fix subreddit breakdown when empty activities array 2022-08-25 16:30:15 -04:00
FoxxMD
33b60825d9 fix(template): Return empty string if no subreddits in breakdown 2022-08-25 16:16:15 -04:00
FoxxMD
b5202a33ac feat(template): Add subreddit breakdown to template data for Recent and History rule 2022-08-25 10:39:03 -04:00
FoxxMD
c02a2ad622 chore: Bump version constant due to BC 2022-08-23 09:49:12 -04:00
FoxxMD
e9f08915a4 chore: Bump version constant 2022-08-23 09:47:35 -04:00
FoxxMD
4b95ccd0ba feat(docs): Simplify getting started operator instructions
Take advantage of First Time Setup page when no configuration is present to help generate a minimum configuration.
2022-08-23 09:46:54 -04:00
FoxxMD
567a2f0720 feat(action): Implement creating submissions #93
* Create self/link submissions, no reddit media (upload) yet
* Submission can use user modifiers (nsfw, spoiler) and mod modifiers (sticky, distinguish, lock)
* Can create submission in current subreddit (default) or arbitrary subreddit defined in configuration (targets)
  * Can create multiple submissions by defining multiple targets
2022-08-22 14:00:27 -04:00
FoxxMD
61ff402256 feat(config): Allow wikiConfig override at subreddit-level 2022-08-22 10:36:18 -04:00
FoxxMD
9158bda992 feat(comment): Implement arbitrary comment targets #93 2022-08-19 11:01:54 -04:00
247 changed files with 14634 additions and 4276 deletions

View File

@@ -1,7 +1,10 @@
.git
logs
.github
docs
_site
.bundle
vendor
docs/.jekyll-cache
node_modules
coverage
.nyc_output
@@ -13,7 +16,7 @@ coverage
*.json5
*.yaml
*.yml
*.env
# exceptions
!heroku.yml
@@ -22,3 +25,5 @@ coverage
!.mocharc.json
!tsconfig.json
!package*.json
!docker/config/**
!_config.yml

1
.github/FUNDING.yml vendored
View File

@@ -1,2 +1,3 @@
github: [FoxxMD]
patreon: FoxxMD
custom: ["bitcoincash:qqmpsh365r8n9jhp4p8ks7f7qdr7203cws4kmkmr8q"]

3
.github/push-hook-sample.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"ref": "refs/heads/edge"
}

53
.github/workflows/pages.yml vendored Normal file
View File

@@ -0,0 +1,53 @@
# Sample workflow for building and deploying a Jekyll site to GitHub Pages
name: Deploy Jekyll site to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["master"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
# Build job
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.0' # Not needed with a .ruby-version file
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
cache-version: 0 # Increment this number if you need to re-download cached gems
- name: Setup Pages
id: pages
uses: actions/configure-pages@v1
- run: bundle exec jekyll build --baseurl ${{ steps.pages.outputs.base_path }} # defaults output to '/_site'
- name: Upload artifact
uses: actions/upload-pages-artifact@v1 # This will automatically upload an artifact from the '/_site' directory
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1

View File

@@ -1,4 +1,14 @@
name: Publish Docker image to Dockerhub
name: Publish Docker image to registries
# Builds image and tags based on the type of push event:
# * branch push -> tag is branch name IE context-mod:edge
# * release (tag) -> tag is release name IE context-mod:0.13.0
#
# Then pushes tagged images to multiple registries
#
# Based on
# https://github.com/docker/build-push-action/blob/master/docs/advanced/push-multi-registries.md
# https://github.com/docker/metadata-action
on:
push:
@@ -13,8 +23,12 @@ on:
jobs:
push_to_registry:
name: Push Docker image to Docker Hub
name: Build and Push Docker image to registries
runs-on: ubuntu-latest
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
permissions:
packages: write
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v2
@@ -25,12 +39,22 @@ jobs:
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v3
with:
images: foxxmd/context-mod
images: |
foxxmd/context-mod
ghcr.io/foxxmd/context-mod
# generate Docker tags based on the following events/attributes
tags: |
type=raw,value=latest,enable=${{ endsWith(github.ref, 'master') }}
@@ -40,7 +64,8 @@ jobs:
latest=false
- name: Build and push Docker image
uses: docker/build-push-action@v2
if: ${{ !env.ACT }}
uses: docker/build-push-action@v3
with:
context: .
push: ${{ github.event_name != 'pull_request' }}

14
.gitignore vendored
View File

@@ -336,6 +336,7 @@ web_modules/
# dotenv environment variables file
.env
.env.test
*.env
# parcel-bundler cache (https://parceljs.org/)
.cache
@@ -380,6 +381,17 @@ dist
.yarn/install-state.gz
.pnp.*
# Copied from https://github.com/github/gitignore/blob/main/Jekyll.gitignore
# Ignore metadata generated by Jekyll
_site/
.sass-cache/
.jekyll-cache/
.jekyll-metadata
# Ignore folders generated by Bundler
.bundle/
vendor/
**/src/**/*.js
**/tests/**/*.js
**/tests/**/*.map
@@ -391,6 +403,8 @@ dist
*.json5
!src/Schema/*.json
!.github/push-hook-sample.json
!docs/**/*.json5
!docs/**/*.yaml
!docs/**/*.json
!docker/config/**

View File

@@ -9,6 +9,9 @@
<excludeFolder url="file://$MODULE_DIR$/src/logs" />
<excludeFolder url="file://$MODULE_DIR$/coverage" />
<excludeFolder url="file://$MODULE_DIR$/.nyc_output" />
<excludeFolder url="file://$MODULE_DIR$/_site" />
<excludeFolder url="file://$MODULE_DIR$/docs/.jekyll-cache" />
<excludeFolder url="file://$MODULE_DIR$/vendor" />
</content>
<content url="file://$MODULE_DIR$/node_modules" />
<orderEntry type="inheritedJdk" />

View File

@@ -96,11 +96,26 @@ WORKDIR /app
FROM base as build
# copy NPM dependencies and install
COPY --chown=abc:abc package*.json ./
COPY --chown=abc:abc tsconfig.json .
RUN npm install
# copy bundle/jekyll dependencies and docs folder
COPY --chown=abc:abc Gemfile Gemfile.lock _config.yml ./
COPY --chown=abc:abc docs ./docs/
# sassc (a jekll dependency) is very slow to compile bc there are no alpine binaries
# https://github.com/sass/sassc-ruby/issues/189#issuecomment-629758948
# so for now sync used jekyll version with prebuilt binary available in alpine repo
RUN apk add --no-cache --virtual .build-deps \
ruby-jekyll \
&& bundle install \
&& jekyll build -b /docs \
&& apk del .build-deps \
&& rm -rf docs
COPY --chown=abc:abc . /app
RUN npm run build && rm -rf node_modules

19
Gemfile Normal file
View File

@@ -0,0 +1,19 @@
source 'https://rubygems.org'
# sassc (a jekll dependency) is very slow to compile bc there are no alpine binaries
# https://github.com/sass/sassc-ruby/issues/189#issuecomment-629758948
# so for now sync used jekyll version with prebuilt binary available in alpine repo
gem "jekyll", "4.2.2" # installed by `gem jekyll`
# gem "webrick" # required when using Ruby >= 3 and Jekyll <= 4.2.2
gem "just-the-docs", "0.4.0.rc3" # currently the latest pre-release
# gem "just-the-docs" # the latest release - currently 0.3.3
gem "jekyll-readme-index"
gem 'jekyll-default-layout'
gem 'jekyll-titles-from-headings'
gem 'jekyll-relative-links'
group :jekyll_plugins do
gem 'jekyll-optional-front-matter'
end

90
Gemfile.lock Normal file
View File

@@ -0,0 +1,90 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.1)
public_suffix (>= 2.0.2, < 6.0)
colorator (1.1.0)
concurrent-ruby (1.1.10)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0)
eventmachine (1.2.7)
ffi (1.15.5)
forwardable-extended (2.6.0)
http_parser.rb (0.8.0)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
jekyll (4.2.2)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
i18n (~> 1.0)
jekyll-sass-converter (~> 2.0)
jekyll-watch (~> 2.0)
kramdown (~> 2.3)
kramdown-parser-gfm (~> 1.0)
liquid (~> 4.0)
mercenary (~> 0.4.0)
pathutil (~> 0.9)
rouge (~> 3.0)
safe_yaml (~> 1.0)
terminal-table (~> 2.0)
jekyll-default-layout (0.1.5)
jekyll (>= 3.0, < 5.0)
jekyll-optional-front-matter (0.3.2)
jekyll (>= 3.0, < 5.0)
jekyll-readme-index (0.3.0)
jekyll (>= 3.0, < 5.0)
jekyll-relative-links (0.6.1)
jekyll (>= 3.3, < 5.0)
jekyll-sass-converter (2.2.0)
sassc (> 2.0.1, < 3.0)
jekyll-seo-tag (2.8.0)
jekyll (>= 3.8, < 5.0)
jekyll-titles-from-headings (0.5.3)
jekyll (>= 3.3, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
just-the-docs (0.4.0.rc3)
jekyll (>= 3.8.5)
jekyll-seo-tag (>= 2.0)
rake (>= 12.3.1)
kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3)
listen (3.7.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.4.0)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (5.0.0)
rake (13.0.6)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.5)
rouge (3.30.0)
safe_yaml (1.0.5)
sassc (2.4.0)
ffi (~> 1.9)
terminal-table (2.0.0)
unicode-display_width (~> 1.1, >= 1.1.1)
unicode-display_width (1.8.0)
PLATFORMS
x86_64-linux
DEPENDENCIES
jekyll (= 4.2.2)
jekyll-default-layout
jekyll-optional-front-matter
jekyll-readme-index
jekyll-relative-links
jekyll-titles-from-headings
just-the-docs (= 0.4.0.rc3)
BUNDLED WITH
2.3.25

View File

@@ -1,9 +1,13 @@
---
title: Home
nav_order: 1
---
# ContextMod [![Latest Release](https://img.shields.io/github/v/release/foxxmd/context-mod)](https://github.com/FoxxMD/context-mod/releases) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Docker Pulls](https://img.shields.io/docker/pulls/foxxmd/context-mod)](https://hub.docker.com/r/foxxmd/context-mod)
<img src="/docs/logo.png" align="right"
alt="ContextMod logo" width="180" height="176">
**Context Mod** (CM) is an event-based, [reddit](https://reddit.com) moderation bot built on top of [snoowrap](https://github.com/not-an-aardvark/snoowrap) and written in [typescript](https://www.typescriptlang.org/).
[**Context Mod**](https://contextmod.dev/) (CM) is an event-based, [reddit](https://reddit.com) moderation bot built on top of [snoowrap](https://github.com/not-an-aardvark/snoowrap) and written in [typescript](https://www.typescriptlang.org/).
It is designed to help fill in the gaps for [automoderator](https://www.reddit.com/wiki/automoderator/full-documentation) in regard to more complex behavior with a focus on **user-history based moderation.**
@@ -16,25 +20,27 @@ An example of the above that Context Bot can do:
Feature Highlights for **Moderators:**
* Complete bot **autonomy**. YAML config is [stored in your subreddit's wiki](/docs/subreddit/gettingStarted.md#setup-wiki-page) (like automoderator)
* Complete bot **autonomy**. YAML config is [stored in your subreddit's wiki](/docs/moderators/gettingStarted.md#setup-wiki-page) (like automoderator)
* Simple rule-action behavior can be combined to create **complex behavior detection**
* Support Activity filtering based on:
* [Author criteria](/docs/subreddit/components/README.md#author-filter) (name, css flair/text, age, karma, moderator status, [Toolbox User Notes](https://www.reddit.com/r/toolbox/wiki/docs/usernotes), and more!)
* [Activity state](/docs/subreddit/components/README.md#item-filter) (removed, locked, distinguished, etc...)
* State of Subreddit Activity is in [Subreddit](/docs/subreddit/components/README.md#subreddit-filter) (nsfw, name, profile, etc...)
* Rules and Actions support [named references](/docs/subreddit/components/README.md#named-rules) -- **write once, reference anywhere**
* Powerful [logic control](/docs/subreddit/components/advancedConcepts/flowControl.md) (if, then, goto)
* [Delay/re-process activities](/docs/subreddit/components/README.md#dispatch) using arbitrary rules
* [**Image Comparisons**](/docs/imageComparison.md) via fingerprinting and/or pixel differences
* [**Repost detection**](/docs/subreddit/components/repost) with support for external services (youtube, etc...)
* [Author criteria](docs/subreddit-configuration/in-depth/filters/README.md#author-filter) (name, css flair/text, age, karma, moderator status, [Toolbox User Notes](https://www.reddit.com/r/toolbox/wiki/docs/usernotes), and more!)
* [Activity state](docs/subreddit-configuration/in-depth/filters/README.md#item-filter) (removed, locked, distinguished, etc...)
* State of Subreddit Activity is in [Subreddit](docs/subreddit-configuration/in-depth/filters/README.md#subreddit-filter) (nsfw, name, profile, etc...)
* Rules and Actions support [named references](docs/subreddit-configuration/README.md#named-rules) -- **write once, reference anywhere**
* Powerful [logic control](docs/subreddit-configuration/advancedConcepts/flowControl.md) (if, then, goto)
* [Delay/re-process activities](docs/subreddit-configuration/README.md#dispatch) using arbitrary rules
* [**Image Comparisons**](docs/subreddit-configuration/imageComparison.md) via fingerprinting and/or pixel differences
* [**Repost detection**](docs/subreddit-configuration/in-depth/repost) with support for external services (youtube, etc...)
* Event notification via Discord
* [**Web interface**](#web-ui-and-screenshots) for monitoring, administration, and oauth bot authentication
* [**Placeholders**](/docs/subreddit/actionTemplating.md) (like automoderator) can be configured via a wiki page or raw text and supports [mustache](https://mustache.github.io) templating
* [**Partial Configurations**](/docs/subreddit/components/README.md#partial-configurations) -- offload parts of your configuration to shared locations to consolidate logic between multiple subreddits
* [**Placeholders**](docs/subreddit-configuration/actionTemplating.md) (like automoderator) can be configured via a wiki page or raw text and supports [mustache](https://mustache.github.io) templating
* [**Partial Configurations**](docs/subreddit-configuration/README.md#partial-configurations) -- offload parts of your configuration to shared locations to consolidate logic between multiple subreddits
* [Guest Access](docs/moderators/README.md#guest-access) enables collaboration and easier setup by allowing temporary access
* [Toxic content prediction](docs/subreddit-configuration/README.md#moderatehatespeechcom-predictions) using [moderatehatespeech.com](https://moderatehatespeech.com) machine learning model
Feature highlights for **Developers and Hosting (Operators):**
* [Server/client architecture](/docs/serverClientArchitecture.md)
* [Server/client architecture](/docs/operator/serverClientArchitecture.md)
* Default/no configuration runs "All In One" behavior
* Additional configuration allows web interface to connect to multiple servers
* Each server instance can run multiple reddit accounts as bots
@@ -42,7 +48,7 @@ Feature highlights for **Developers and Hosting (Operators):**
* [Database Persistence](/docs/operator/database.md) using SQLite, MySql, or Postgres
* Audit trails for bot activity
* Historical statistics
* [Docker container support](/docs/operator/installation.md#docker-recommended)
* [Docker container](/docs/operator/installation.md#docker-recommended) and [docker-compose](/docs/operator/installation.md#docker-compose) support
* Easy, UI-based [OAuth authentication](/docs/operator/addingBot.md) for adding Bots and moderator dashboard
* Integration with [InfluxDB](https://www.influxdata.com) for detailed [time-series metrics](/docs/operator/database.md#influx) and a pre-built [Grafana](https://grafana.com) [dashboard](/docs/operator/database.md#grafana)
@@ -57,7 +63,7 @@ Feature highlights for **Developers and Hosting (Operators):**
Each subreddit using the RCB bot configures its behavior via their own wiki page.
When a monitored **Activity** (new comment/submission, new modqueue item, etc.) is detected the bot runs through a list of [**Checks**](/docs/subreddit/components/README.md#checks) to determine what to do with the **Activity** from that Event. Each **Check** consists of :
When a monitored **Activity** (new comment/submission, new modqueue item, etc.) is detected the bot runs through a list of [**Checks**](docs/subreddit-configuration/README.md#checks) to determine what to do with the **Activity** from that Event. Each **Check** consists of :
#### Kind
@@ -65,11 +71,11 @@ Is this check for a submission or comment?
#### Rules
A list of [**Rules**](/docs/subreddit/components/README.md#rules) to run against the **Activity**. Triggered Rules can cause the whole Check to trigger and run its **Actions**
A list of [**Rules**](docs/subreddit-configuration/README.md#rules) to run against the **Activity**. Triggered Rules can cause the whole Check to trigger and run its **Actions**
#### Actions
A list of [**Actions**](/docs/subreddit/components/README.md#actions) that describe what the bot should do with the **Activity** or **Author** of the activity (comment, remove, approve, etc.). The bot will run **all** Actions in this list.
A list of [**Actions**](docs/subreddit-configuration/README.md#actions) that describe what the bot should do with the **Activity** or **Author** of the activity (comment, remove, approve, etc.). The bot will run **all** Actions in this list.
___
@@ -93,14 +99,14 @@ See the [Operator's Getting Started Guide](/docs/operator/gettingStarted.md)
This guide is for **reddit moderators** who want to configure an existing CM bot to run on their subreddit.
See the [Moderator's Getting Started Guide](/docs/subreddit/gettingStarted.md)
See the [Moderator's Getting Started Guide](/docs/moderators/gettingStarted.md)
## Configuration and Documentation
Context Bot's configuration can be written in YAML (like automoderator) or [JSON5](https://json5.org/). Its schema conforms to [JSON Schema Draft 7](https://json-schema.org/). Additionally, many **operator** settings can be passed via command line or environmental variables.
* For **operators** (running the bot instance) see the [Operator Configuration](/docs/operator/configuration.md) guide
* For **moderators** consult the [app schema and examples folder](/docs/README.md#configuration-and-usage)
* For **moderators** consult the [Subreddit Configuration Docs](/docs/subreddit-configuration/README.md)
[**Check the full docs for in-depth explanations of all concepts and examples**](/docs)
@@ -134,6 +140,10 @@ Moderator view/invite and authorization:
![Invite View](docs/images/oauth-invite.jpg)
A similar helper and invitation experience is available for adding **subreddits to an existing bot.**
![Subreddit Invite View](docs/images/subredditInvite.jpg)
### Configuration Editor
A built-in editor using [monaco-editor](https://microsoft.github.io/monaco-editor/) makes editing configurations easy:

45
_config.yml Normal file
View File

@@ -0,0 +1,45 @@
title: ContextMod
description: Documentation for ContextMod
theme: just-the-docs
source: docs
url: https://contextmod.dev
color_scheme: dark
mermaid:
version: "9.1.3"
aux_links:
Github: https://github.com/foxxmd/context-mod
plugins:
- jekyll-readme-index
- jekyll-default-layout
- jekyll-titles-from-headings
- jekyll-optional-front-matter
- jekyll-relative-links
titles_from_headings:
enabled: true
strip_title: false
collections: false
readme_index:
enabled: true
remove_originals: true
with_frontmatter: true
optional_front_matter:
remove_originals: true
defaults:
- scope:
path: ""
values:
has_toc: false
- scope:
path: "images"
values:
image: true

3
act.env.example Normal file
View File

@@ -0,0 +1,3 @@
GITHUB_TOKEN=
DOCKERHUB_USERNAME=
DOCKER_PASSWORD=

62
docker-compose.yml Normal file
View File

@@ -0,0 +1,62 @@
version: '3.7'
services:
app:
image: foxxmd/context-mod:latest
# use the settings below, instead of 'image', if running context-mod from the repository (developing local changes)
# build:
# context: .
volumes:
# Location of config file to use with CM
# The path BEFORE the colon (:) is the path on the host machine
# which defaults to a folder named 'data' in the same directory this file is run in.
- './data:/config'
# For a new installation you should use the config from the repository included for use with docker-compose
# https://github.com/FoxxMD/context-mod/blob/master/docker/config/docker-compose/config.yaml
# Copy config.yaml to /(this directory)/data/config.yaml and then modify to match any changed settings below (see comments on config.yaml)
ports:
- "${CM_WEB-8085}:8085"
environment:
IS_DOCKER: true
# If using a linux host, uncomment these and set them accordingly https://github.com/FoxxMD/context-mod/blob/master/docs/operator/installation.md#linux-host
# PUID: 1000
# PGID: 1000
cache:
image: 'redis:7-alpine'
volumes:
# on linux will need to make sure this directory has correct permissions for container to access
- './data/cache:/data'
database:
image: 'mariadb:10.9.3'
environment:
MYSQL_ROOT_PASSWORD: CHANGE_THIS
MYSQL_USER: cmuser
# this should match the password set in config.yaml
MYSQL_PASSWORD: CHANGE_THIS
MYSQL_DATABASE: ContextMod
volumes:
- './data/db:/var/lib/mysql'
influx:
image: 'influxdb:latest'
volumes:
- './data/influx:/var/lib/influxdb2'
ports:
- "${INFLUX_WEB:-8086}:8086"
profiles:
- full
grafana:
image: 'grafana/grafana'
volumes:
- './data/grafana:/var/lib/grafana'
ports:
- "${GRAFANA_WEB:-3000}:3000"
environment:
GF_SECURITY_ADMIN_PASSWORD: CHANGE_THIS
depends_on:
- influx
profiles:
- full

View File

@@ -0,0 +1,43 @@
operator:
name: CHANGE_THIS #YOUR REDDIT USERNAME HERE
logging:
# default level for all transports
level: debug
file:
# override default level
level: warn
# true -> log folder at projectDir/log
dirname: true
caching:
provider:
store: redis
host: cache
port: 6379
prefix: prod
databaseConfig:
migrations:
continueOnAutomatedBackup: true
#force: true # uncomment this to make cm run new migrations without confirmation
#logging: ['query', 'error', 'warn', 'log'] # uncomment this to get typeorm to log EVERYTHING
connection:
type: 'mariadb'
host: 'database'
username: 'cmuser'
# This should match the password set in docker-compose.yaml
password: 'CHANGE_THIS'
database: 'ContextMod'
web:
credentials:
redirectUri: 'http://localhost:8085/callback'
session:
storage: cache
port: 8085
#
# Influx/Grafana requires additional configuration. See https://github.com/FoxxMD/context-mod/blob/master/docs/operator/database.md#influx
#
#influxConfig:
# credentials:
# url: 'http://influx:8086'
# token: 'YourInfluxToken'
# org: YourInfluxOrg
# bucket: contextmod

View File

@@ -1,4 +1,8 @@
# Documentation
---
title: Overview
permalink: /overview.html
nav_order: 2
---
# Table of Contents
@@ -22,8 +26,8 @@
Review **at least** the **How It Works** and **Concepts** below, then:
* For **Operators** (running a bot instance) refer to [**Operator Getting Started**](/docs/operator/gettingStarted.md) guide
* For **Moderators** (configuring an existing bot for your subreddit) refer to the [**Moderator Getting Started**](/docs/subreddit/gettingStarted.md) guide
* For **Operators** (running a bot instance) refer to [**Operator Getting Started**](operator/gettingStarted.md) guide
* For **Moderators** (configuring an existing bot for your subreddit) refer to the [**Moderator Getting Started**](moderators/gettingStarted.md) guide
## How It Works
@@ -33,10 +37,10 @@ Where possible Context Mod (CM) uses the same terminology as, and emulates the b
Expand the section below for a simplified flow diagram of how CM processes an incoming Activity. Then refer the text description of the diagram below as well as [Concepts](#Concepts) for descriptions of individual components.
<details>
<details markdown="block">
<summary>Diagram</summary>
![Flow Diagram](/docs/images/diagram-highlevel.jpg)
![Flow Diagram](images/diagram-highlevel.jpg)
</details>
@@ -92,7 +96,7 @@ An example of Runs:
Both group of Checks are independent of each other (don't have any patterns or actions in common).
[Full Documentation for Runs](/docs/subreddit/components/README.md#runs)
[Full Documentation for Runs](subreddit-configuration/README.md#runs)
### Checks
@@ -105,7 +109,7 @@ A Run can be made up of one or more **Checks** that are processed **in the order
Once a Check is **triggered** (its Rules are satisfied and Actions performed) all subsequent Checks are skipped.
[Full Documentation for Checks](/docs/subreddit/components/README.md#checks)
[Full Documentation for Checks](subreddit-configuration/README.md#checks)
### Rule
@@ -113,11 +117,11 @@ A **Rule** is some set of **criteria** (conditions) that are tested against an A
CM has different **Rules** that can test against different types of behavior and aspects of a User, their history, and the Activity (submission/common) being checked.
[Full Documentation for Rules](/docs/subreddit/components/README.md#rules)
[Full Documentation for Rules](subreddit-configuration/README.md#rules)
#### Available Rules
All available rules can be found in the [components documentation](/docs/subreddit/components/README.md#rules)
All available rules can be found in the [components documentation](subreddit-configuration/README.md#rules)
### Rule Set
@@ -127,7 +131,7 @@ Rule Sets can be used interchangeably with other **Rules** and **Rule Sets** in
They allow you to create more complex trigger behavior by combining multiple rules into one "parent rule".
[Rule Sets Documentation](/docs/subreddit/components/README.md#rule-sets)
[Rule Sets Documentation](subreddit-configuration/README.md#rule-sets)
### Action
@@ -135,7 +139,7 @@ An **Action** is some action the bot can take against the checked Activity (comm
#### Available Actions
[Available Actions Documentation](/docs/subreddit/components/README.md#list-of-actions)
[Available Actions Documentation](subreddit-configuration/README.md#list-of-actions)
### Filters
@@ -146,13 +150,14 @@ An **Action** is some action the bot can take against the checked Activity (comm
* When the filter test **passes** the thing being tested continues to process as usual
* When the filter test **fails** the thing being tested **fails**.
[Full Documentation for Filters](/docs/subreddit/components/README.md#filters)
[Full Documentation for Filters](subreddit-configuration/README.md#filters)
## Configuration And Usage
* For **Operator/Bot maintainers** see **[Operation Guide](/docs/operator/README.md)**
* For **Operator/Bot maintainers** see **[Operation Guide](operator/README.md)**
* For **Moderators**
* Refer to the [Subreddit Components Documentation](/docs/subreddit/components) or the [subreddit-ready examples](/docs/subreddit/components/subredditReady)
* Start with the [Subreddit/Moderator docs](moderators/README.md) or [Moderator Getting Started guide](moderators/gettingStarted.md)
* Refer to the [Subreddit Components Documentation](subreddit-configuration) or the [subreddit-ready examples](subreddit-configuration/cookbook)
* as well as the [schema](https://json-schema.app/view/%23?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Fcontext-mod%2Fmaster%2Fsrc%2FSchema%2FApp.json) which has
* fully annotated configuration data/structure
* generated examples in json/yaml

View File

@@ -1,4 +1,40 @@
TODO add more development sections...
---
nav_order: 7
---
# Development
# Serving Docs Locally
Requirements:
* [Jeykll](https://jekyllrb.com/) installed
* Ruby 2.5.0 or higher and [RubyGems](https://rubygems.org/pages/download) (usually bundled)
* [Bundler](https://bundler.io/) installed
## Install Doc Dependencies
```bash
npm run docs-install
```
## Serve Docs
```bash
npm run docs-start
```
# Developing/Testing Github Actions
Use [act](https://github.com/nektos/act) to run Github actions locally.
An example secrets file can be found in the project working directory at [act.env.example](../act.env.example)
Modify [push-hook-sample.json](../.github/push-hook-sample.json) to point to the local branch you want to run a `push` event trigger on, then run this command from the project working directory:
```bash
act -e .github/push-hook-sample.json --secret-file act.env
```
# Mocking Reddit API
@@ -16,7 +52,7 @@ Map port `1080:1080` -- acts as both the proxy port and the UI endpoint with the
http(s)://localhost:1080/mockserver/dashboard
```
In your [operator configuration](/docs/operator/operatorConfiguration.md) define a proxy for snoowrap at the top-level:
In your [operator configuration](operator/configuration.md) define a proxy for snoowrap at the top-level:
```yaml
snoowrap:
@@ -47,7 +83,7 @@ Content-Length: 155
--data-raw '{
"httpRequest": {},
"priority": 0,
"httpForward": {
"httpForward": {
"host": "oauth.reddit.com",
"port": 443,
"scheme": "HTTPS"
@@ -83,7 +119,7 @@ The lifecycle of a mock call I do:
Content-Type: application/json
Content-Length: 1757
```
```
</details>
@@ -166,7 +202,7 @@ Content-Length: 1757
```
</details>
#### All Responses Timeout
<details markdown="block">
@@ -248,7 +284,7 @@ curl --location --request PUT 'http://localhost:8010/mockserver/expectation' \
### Clearing Behavior
```HTTP
```HTTP
PUT /mockserver/clear?type=EXPECTATIONS HTTP/1.1
Host: localhost:8010
Content-Type: application/json
@@ -275,7 +311,7 @@ Content-Length: 251
</details>
<details>
<details markdown="block">
<summary>CURL</summary>
```bash
@@ -301,7 +337,7 @@ curl --location --request PUT 'http://localhost:8010/mockserver/expectation' \
#### All Responses Drop After Delay (Connection Closed by Server)
<details>
<details markdown="block">
<summary>HTTP</summary>
```HTTP
@@ -328,7 +364,7 @@ Content-Length: 234
</details>
<details>
<details markdown="block">
<summary>CURL</summary>
```bash
@@ -366,7 +402,7 @@ Content-Length: 26
}
```
<details>
<details markdown="block">
<summary>CURL</summary>
```bash

BIN
docs/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 133 KiB

BIN
docs/images/guests.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 KiB

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 479 KiB

After

Width:  |  Height:  |  Size: 225 KiB

169
docs/index.md Normal file
View File

@@ -0,0 +1,169 @@
---
title: Home
nav_order: 1
---
# ContextMod [![Latest Release](https://img.shields.io/github/v/release/foxxmd/context-mod)](https://github.com/FoxxMD/context-mod/releases) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Docker Pulls](https://img.shields.io/docker/pulls/foxxmd/context-mod)](https://hub.docker.com/r/foxxmd/context-mod)
<img src="/logo.png" align="right"
alt="ContextMod logo" width="180" height="176">
[**Context Mod**](https://contextmod.dev/) (CM) is an event-based, [reddit](https://reddit.com) moderation bot built on top of [snoowrap](https://github.com/not-an-aardvark/snoowrap) and written in [typescript](https://www.typescriptlang.org/).
It is designed to help fill in the gaps for [automoderator](https://www.reddit.com/wiki/automoderator/full-documentation) in regard to more complex behavior with a focus on **user-history based moderation.**
An example of the above that Context Bot can do:
> * On a new submission, check if the user has also posted the same link in **N** number of other subreddits within a timeframe/# of posts
> * On a new submission or comment, check if the user has had any activity (sub/comment) in **N** set of subreddits within a timeframe/# of posts
>
>In either instance Context Bot can then perform any action a moderator can (comment, report, remove, lock, etc...) against that user, comment, or submission.
Feature Highlights for **Moderators:**
* Complete bot **autonomy**. YAML config is [stored in your subreddit's wiki](moderators/gettingStarted.md#setup-wiki-page) (like automoderator)
* Simple rule-action behavior can be combined to create **complex behavior detection**
* Support Activity filtering based on:
* [Author criteria](subreddit-configuration/in-depth/filters/README.md#author-filter) (name, css flair/text, age, karma, moderator status, [Toolbox User Notes](https://www.reddit.com/r/toolbox/wiki/usernotes), and more!)
* [Activity state](subreddit-configuration/in-depth/filters/README.md#item-filter) (removed, locked, distinguished, etc...)
* State of Subreddit Activity is in [Subreddit](subreddit-configuration/in-depth/filters/README.md#subreddit-filter) (nsfw, name, profile, etc...)
* Rules and Actions support [named references](subreddit-configuration/README.md#named-rules) -- **write once, reference anywhere**
* Powerful [logic control](subreddit-configuration/advancedConcepts/flowControl.md) (if, then, goto)
* [Delay/re-process activities](subreddit-configuration/README.md#dispatch) using arbitrary rules
* [**Image Comparisons**](subreddit-configuration/imageComparison.md) via fingerprinting and/or pixel differences
* [**Repost detection**](subreddit-configuration/in-depth/repost) with support for external services (youtube, etc...)
* Event notification via Discord
* [**Web interface**](#web-ui-and-screenshots) for monitoring, administration, and oauth bot authentication
* [**Placeholders**](subreddit-configuration/actionTemplating.md) (like automoderator) can be configured via a wiki page or raw text and supports [mustache](https://mustache.github.io) templating
* [**Partial Configurations**](subreddit-configuration/README.md#partial-configurations) -- offload parts of your configuration to shared locations to consolidate logic between multiple subreddits
* [Guest Access](moderators/README.md#guest-access) enables collaboration and easier setup by allowing temporary access
* [Toxic content prediction](subreddit-configuration/README.md#moderatehatespeechcom-predictions) using [moderatehatespeech.com](https://moderatehatespeech.com) machine learning model
Feature highlights for **Developers and Hosting (Operators):**
* [Server/client architecture](operator/serverClientArchitecture.md)
* Default/no configuration runs "All In One" behavior
* Additional configuration allows web interface to connect to multiple servers
* Each server instance can run multiple reddit accounts as bots
* Global/subreddit-level [**caching**](operator/caching.md) of Reddit APIs responses and CM results
* [Database Persistence](operator/database.md) using SQLite, MySql, or Postgres
* Audit trails for bot activity
* Historical statistics
* [Docker container](operator/installation.md#docker-recommended) and [docker-compose](operator/installation.md#docker-compose) support
* Easy, UI-based [OAuth authentication](operator/addingBot.md) for adding Bots and moderator dashboard
* Integration with [InfluxDB](https://www.influxdata.com) for detailed [time-series metrics](operator/database.md#influx) and a pre-built [Grafana](https://grafana.com) [dashboard](operator/database.md#grafana)
# Table of Contents
* [How It Works](#how-it-works)
* [Getting Started](#getting-started)
* [Configuration And Documentation](#configuration-and-documentation)
* [Web UI and Screenshots](#web-ui-and-screenshots)
### How It Works
Each subreddit using the RCB bot configures its behavior via their own wiki page.
When a monitored **Activity** (new comment/submission, new modqueue item, etc.) is detected the bot runs through a list of [**Checks**](subreddit-configuration/README.md#checks) to determine what to do with the **Activity** from that Event. Each **Check** consists of :
#### Kind
Is this check for a submission or comment?
#### Rules
A list of [**Rules**](subreddit-configuration/README.md#rules) to run against the **Activity**. Triggered Rules can cause the whole Check to trigger and run its **Actions**
#### Actions
A list of [**Actions**](subreddit-configuration/README.md#actions) that describe what the bot should do with the **Activity** or **Author** of the activity (comment, remove, approve, etc.). The bot will run **all** Actions in this list.
___
The **Checks** for a subreddit are split up into **Submission Checks** and **Comment Checks** based on their **kind**. Each list of checks is run independently based on when events happen (submission or comment).
When an Event occurs all Checks of that type are run in the order they were listed in the configuration. When one check is triggered (an Action is performed) the remaining checks will not be run.
___
[Learn more about the RCB lifecycle and core concepts in the docs.](/README.md#how-it-works)
## Getting Started
#### Operators
This guide is for users who want to **run their own bot on a ContextMod instance.**
See the [Operator's Getting Started Guide](operator/gettingStarted.md)
#### Moderators
This guide is for **reddit moderators** who want to configure an existing CM bot to run on their subreddit.
See the [Moderator's Getting Started Guide](moderators/gettingStarted.md)
## Configuration and Documentation
Context Bot's configuration can be written in YAML (like automoderator) or [JSON5](https://json5.org/). Its schema conforms to [JSON Schema Draft 7](https://json-schema.org/). Additionally, many **operator** settings can be passed via command line or environmental variables.
* For **operators** (running the bot instance) see the [Operator Configuration](operator/configuration.md) guide
* For **moderators** consult the [Subreddit Configuration Docs](subreddit-configuration/README.md)
[**Check the full docs for in-depth explanations of all concepts and examples**](/docs)
## Web UI and Screenshots
### Dashboard
CM comes equipped with a dashboard designed for use by both moderators and bot operators.
* Authentication via Reddit OAuth -- only accessible if you are the bot operator or a moderator of a subreddit the bot moderates
* Connect to multiple ContextMod instances (specified in configuration)
* Monitor API usage/rates
* Monitoring and administration **per subreddit:**
* Start/stop/pause various bot components
* View statistics on bot usage (# of events, checks run, actions performed) and cache usage
* View various parts of your subreddit's configuration and manually update configuration
* View **real-time logs** of what the bot is doing on your subreddit
* **Run bot on any permalink**
![Subreddit View](images/subredditStatus.jpg)
### Bot Setup/Authentication
A bot oauth helper allows operators to define oauth credentials/permissions and then generate unique, one-time invite links that allow moderators to authenticate their own bots without operator assistance. [Learn more about using the oauth helper.](operator/addingBot.md#cm-oauth-helper-recommended)
Operator view/invite link generation:
![Oauth View](images/oauth.jpg)
Moderator view/invite and authorization:
![Invite View](images/oauth-invite.jpg)
A similar helper and invitation experience is available for adding **subreddits to an existing bot.**
![Subreddit Invite View](images/subredditInvite.jpg)
### Configuration Editor
A built-in editor using [monaco-editor](https://microsoft.github.io/monaco-editor/) makes editing configurations easy:
* Automatic JSON or YAML syntax validation and formatting
* Automatic Schema (subreddit or operator) validation
* All properties are annotated via hover popups
* Unauthenticated view via `yourdomain.com/config`
* Authenticated view loads subreddit configurations by simple link found on the subreddit dashboard
* Switch schemas to edit either subreddit or operator configurations
![Configuration View](images/editor.jpg)
### [Grafana Dashboard](operator/database.md#grafana)
* Overall stats (active bots/subreddits, api calls, per second/hour/minute activity ingest)
* Over time graphs for events, per subreddit, and for individual rules/check/actions
![Grafana Dashboard](images/grafana.jpg)
## License
[MIT](/LICENSE)

101
docs/moderators/README.md Normal file
View File

@@ -0,0 +1,101 @@
---
has_children: true
title: Moderators
nav_order: 3
---
This section is for **reddit moderators**. It covers how to use a CM bot for your subreddit.
If you are trying to run a ContextMod instance (the actual software) please refer to the [operator section](../operator/README.md).
# Table of Contents
* [Overview](#overview)
* [Your Relationship to CM](#your-relationship-to-cm)
* [Operator](#operator)
* [Your Bot](#your-bot)
* [Getting Started](#getting-started)
* [Accessing The Bot](#accessing-the-bot)
* [Editing The Bot](#editing-the-bot)
* [Configuration](#configuration)
* [Guest Access](#guest-access)
# Overview
The Context Mod **software** can manage multiple **bots** (reddit accounts used as bots, like `/u/MyCMBot`). Each bot can manage (run) multiple **subreddits** which is determined by the subreddits the account is a moderator of.
You, the moderator of a subreddit a CM bot runs in, can access/manage the Bot using the CM software's [web interface](../images/subredditStatus.jpg) and control its behavior using the [web editor.](../images/editor.jpg)
## Your Relationship to CM
It is important to understand the relationship between you (the moderator), the bot, and the operator (the person running the CM software).
The easiest way to think about this is in relation to how you use Automoderator and interact with Reddit as a moderator. As an analogy:
### Operator
The operator is the person running the actual server/machine the Context Mod software is on.
They are best thought of as **Reddit:**
* Mostly hands-off when it comes to the bot and interacting with your subreddit
* You must interact with Reddit first before you can use automoderator (login, create a subreddit, etc...)
Unlike reddit, though, there is a greater level of trust required between you and the Operator because what you make the Bot do ultimately affects the Operator since they are the ones actually running your Bot and making API calls to reddit.
### Your Bot
Your bot is like an **invite-only version of Automoderator**:
* Unlike automoderator, you **must** interact with the Operator in order to get the bot working. It is not public for anyone to use.
* Like automoderator, you **must** create a [configuration](../subreddit-configuration/README.md) for it do anything.
* The bot does not come pre-configured for you. It is a blank slate and requires user input to be useful.
* Also like automoderator, you are **entirely in control of the bot.**
* You can start, stop, and edit its behavior at any time without needing to communicate with the Operator.
* CM provides you _tools_, different ways the Bot can detect patterns in your subreddit/users as well as actions it can, and you can decide to use them however you want.
* Your bot is **only accessible to moderators of your subreddit.**
# Getting Started
The [Getting Started](gettingStarted.md) guide lays out the steps needed to go from nothing to a working Bot. If you are a moderator new to Context Mod this is where you want to begin.
# Accessing The Bot
All bot management and editing is done through the [web interface.](/../images/subredditStatus.jpg) The URL used for accessing this interface is given to you by the **Operator** once they have agreed to host your bot/subreddit.
NOTE: This interface is **only access to moderators of your subreddit** and [guests.](#guest-access) You must login to the web interface **with your moderator account** in order to access it.
A **guided tour** that helps show how to manage the bot at a high-level is available on the web interface by clicking the **Help** button in the top-right of the page.
## Editing The Bot
Find the [editor in the web interface](../webInterface.md#editingupdating-your-config) to access the built-in editor for the bot.
[The editor](../images/editor.jpg) should be your all-in-one location for viewing and editing your bot's behavior. **It is equivalent to Automoderator's editor page.**
The editor features:
* syntax validation and highlighting
* configuration auto-complete and documentation (hover over properties)
* built-in validation using Microsoft Word "squiggly lines" indicators and an error list at the bottom of the window
* built-in saving (at the top of the window)
# Configuration
Use the [Configuration Reference](../subreddit-configuration/README.md) to learn about all the different components available for building a CM configuration.
Additionally, refer to [How It Works](../README.md#how-it-works) and [Core Concepts](../README.md#concepts) to learn the basic of CM configuration.
After you have the basics under your belt you could use the [subreddit configurations cookbook](../subreddit-configuration/cookbook) to familiarize yourself with a complete configuration and ways to use CM.
# Guest Access
CM supports **Guest Access**. Reddit users who are given Guest Access to your bot are allowed to access the web interface even though they are not moderators.
Additionally, they can edit the subreddit's config using the bot. If a Guest edits your config their username will be mentioned in the wiki page edit reason.
Guests can do everything a regular mod can except view/add/remove Guest. They can be removed at any time or set with an expiration date that their access is removed on.
**Guests are helpful if you are new to CM and know reddit users that can help you get started.**
[Add guests from the Subreddit tab in the main interface.](../images/guests.jpg)

View File

@@ -1,5 +1,12 @@
---
parent: Moderators
nav_order: 1
---
# Getting Started
This getting started guide is for **reddit moderators** -- that is, someone who wants **an existing ContextMod bot to run on their subreddit.** If you are trying to run a ContextMod
instance (software) please refer to the [operator getting started](/docs/operator/gettingStarted.md) guide.
instance (software) please refer to the [operator getting started](../operator/gettingStarted.md) guide.
# Table of Contents
@@ -14,8 +21,8 @@ instance (software) please refer to the [operator getting started](/docs/operato
Before continuing with this guide you should first make sure you understand how a ContextMod works. Please review this documentation:
* [How It Works](/docs/README.md#how-it-works)
* [Core Concepts](/docs/README.md#concepts)
* [How It Works](../README.md#how-it-works)
* [Core Concepts](../README.md#concepts)
# Choose A Bot
@@ -81,11 +88,11 @@ The default location for this page is at `https://old.reddit.com/r/YOURSUBERDDIT
The bot automatically tries to create its configuration wiki page. You can find the result of this in the log for your subreddit in the web interface.
If this fails for some reason you can create the wiki page through the web interface by navigating to your subreddit's tab, opening the [built-in editor (click **View**)](/docs/images/configBox.png), and following the directions in **Create configuration for...** link found there.
If this fails for some reason you can create the wiki page through the web interface by navigating to your subreddit's tab, opening the [built-in editor (click **View**)](../images/configBox.png), and following the directions in **Create configuration for...** link found there.
If neither of the above approaches work, or you do not wish to use the web interface, expand the section below for directions on how to manually setup the wiki page:
<details>
<details markdown="block">
* Visit the wiki page of the subreddit you want the bot to moderate
* The default location the bot checks for a configuration is at `https://old.reddit.com/r/YOURSUBERDDIT/wiki/botconfig/contextbot`
@@ -104,11 +111,11 @@ If you already have a configuration you may skip the below step and go directly
### Using an Example Config
Visit the [Examples](https://github.com/FoxxMD/context-mod/tree/master/docs/examples) folder to find various examples of individual rules or see the [subreddit-ready examples.](/docs/subreddit/components/subredditReady)
Visit the [Examples](https://github.com/FoxxMD/context-mod/tree/master../examples) folder to find various examples of individual rules or see the [subreddit cookbook examples.](../subreddit-configuration/cookbook)
After you have found a configuration to use as a starting point:
* Copy the URL for the configuration file EX `https://github.com/FoxxMD/context-mod/blob/master/docs/examples/subredditReady/freekarma.json5` and either:
* Copy the URL for the configuration file EX `https://github.com/FoxxMD/context-mod/blob/master../examples/subredditReady/freekarma.json5` and either:
* (Easiest) **Load** it into your [subreddit's built-in editor](#using-the-built-in-editor) and **Save**
* or on the file's page, click the **Raw** button, select all and copy to your clipboard, and [manually save to your wiki page](#manually-saving)
@@ -136,13 +143,13 @@ PROTIP: Find an [example config](#using-an-example-config) to use as a starting
In the web interface each subreddit's tab has access to the built-in editor. Use this built-in editor to automatically create, load, or save the configuration for that subreddit's wiki.
* Visit the tab for the subreddit you want to edit the configuration of
* Open the [built-in editor by click **View**](/docs/images/configBox.png)
* Open the [built-in editor by click **View**](../images/configBox.png)
* Edit your configuration
* Follow the directions on the **Save to r/..** link found at the top of the editor to automatically save your configuration
### Manually Saving
<details>
<details markdown="block">
* Open the wiki page you created in the [wiki setup step](#setup-wiki-page) and click **edit**
* Copy-paste your configuration into the wiki text box

View File

@@ -1,4 +1,9 @@
# Operator Guide
---
has_children: true
nav_order: 4
---
# Operator
An **Operator** is the user **running the ContextMod software.**
@@ -6,35 +11,35 @@ They are responsible for configuring the software at a high-level and managing a
* Creating cache/database servers and configuring their connections in CM
* Provisioning the [Reddit Clients](#provisioning-a-reddit-client) needed to run bots and the CM UI
* Providing [global-level configuration](/docs/operator/configuration.md) that affects general bot/subreddit behavior
* Providing [global-level configuration](configuration.md) that affects general bot/subreddit behavior
* Onboarding new bots/subreddits
# Table of Contents
* [Overview](#overview)
* [Client-Server Architecture](/docs/serverClientArchitecture.md)
* [Getting Started](/docs/operator/gettingStarted.md)
* [Installation](/docs/operator/installation.md)
* [Client-Server Architecture](serverClientArchitecture.md)
* [Getting Started](gettingStarted.md)
* [Installation](installation.md)
* [Provisioning a Reddit Client](#provisioning-a-reddit-client)
* [Configuration](/docs/operator/configuration.md)
* [Adding A Bot](/docs/operator/addingBot.md)
* [Configuration](configuration.md)
* [Adding A Bot](addingBot.md)
# Overview
CM is composed of two applications that operate indepedently but are packaged together such that they act as one piece of software:
CM is composed of two applications that operate independently but are packaged together such that they act as one piece of software:
* **Server** -- Responsible for **running the bot(s)** and providing an API to retrieve information on and interact with them EX start/stop bot, reload config, retrieve operational status, etc.
* **Client** -- Responsible for serving the **web interface** and handling the bot oauth authentication flow between operators and subreddits/bots.
Both applications authenticate, and are primarily operated, by using [Reddit's API through OAuth.](https://github.com/reddit-archive/reddit/wiki/OAuth2) The **Client** uses OAuth to verify the identity of moderators logging into the web interface. The **Server** uses oauth tokens to interact with Reddit's API and operate all the configured bots.
In its default mode of operation CM takes care of all the interaction between **Server** and **Client** for you so that you can effectively treat it as a monolithic application. Learn more about CM's architecture and other operation modes in the [Server-Client Architecture documentation.](/docs/serverClientArchitecture.md)
In its default mode of operation CM takes care of all the interaction between **Server** and **Client** for you so that you can effectively treat it as a monolithic application. Learn more about CM's architecture and other operation modes in the [Server-Client Architecture documentation.](../serverClientArchitecture.md)
# [Getting Started](/docs/operator/gettingStarted.md)
# [Getting Started](gettingStarted.md)
The [Getting Started](/docs/operator/gettingStarted.md) guide serves as a straight-forward "how-to" for standing up a CM server from scratch with minimal explanation.
The [Getting Started](gettingStarted.md) guide serves as a straight-forward "how-to" for standing up a CM server from scratch with minimal explanation.
# [Installation](/docs/operator/installation.md)
# [Installation](installation.md)
CM has many installation options:
@@ -42,7 +47,7 @@ CM has many installation options:
* Built/pulled from a Docker image hosted on Dockerhub
* Deployed to Heroku with a Quick Deploy template (experimental)
Refer to the [Installation](/docs/operator/installation.md) docs for more information.
Refer to the [Installation](installation.md) docs for more information.
# Provisioning A Reddit Client
@@ -60,18 +65,18 @@ Click **create app**.
Then write down your **Client ID, Client Secret, and Redirect Uri** somewhere
# [Configuration](/docs/operator/configuration.md)
# [Configuration](configuration.md)
The [Configuration](/docs/operator/configuration.md) documentation covers:
The [Configuration](configuration.md) documentation covers:
* How CM's configuration can be defined
* How to create and define location for a config file
* Running CM from the command line
* Documentation for configuration on Bots, the web client, API, and more...
# [Adding A Bot](/docs/operator/addingBot.md)
# [Adding A Bot](addingBot.md)
The [Adding A Bot](/docs/operator/addingBot.md) documentation covers:
The [Adding A Bot](addingBot.md) documentation covers:
* What is a Bot?
* What is needed to add a Bot to CM?

View File

@@ -1,3 +1,10 @@
---
parent: Operator
nav_order: 4
---
# Adding A Bot
# Table of Contents
* [What is a Bot?](#what-is-a-bot)
@@ -19,7 +26,7 @@ There is nothing special about the account! What's special is how its used -- th
These things need to be done before a Bot can be added to CM:
* [Provisioned a Reddit Client](/docs/operator/README.md#provisioning-a-reddit-client)
* [Provisioned a Reddit Client](README.md#provisioning-a-reddit-client)
* You or the person who controls the Bot account must have account credentials (username/password). Logging in to reddit is part of the setup process.
* If the bot does not exist **create a reddit account for it.**
* If the bot does exist make sure you are in communication with the owner of the account.
@@ -38,7 +45,7 @@ This method will use CM's built in oauth flow. It is recommended because:
If this is your **first time adding a bot** you must make sure you have
* done the [prerequisites](#prerequisites)
* created a [minimum operator configuration](/docs/operator/configuration.md#minimum-config)
* created a [minimum operator configuration](configuration.md#minimum-config)
* that specifies the client id/secret from provisioning your reddit client
* specified **Operator Name** in the configuration
@@ -56,14 +63,14 @@ Follow the directions in the helper to create a **Bot Invite Link.**
Visit the **Bot Invite Link** while **logged in to reddit as the bot account** to begin the onboarding process. Refer to the [Onboarding Your Bot]() subreddit documentation for more information on this process.
At the end of the onboarding process the bot should be automatically added to your operator configuration. If there is an issue with automatically adding it then the oauth credentials will be displayed at the end of onboarding and can be [manually added to the configuration.](/docs/operator/configuration.md#manually-adding-a-bot)
At the end of the onboarding process the bot should be automatically added to your operator configuration. If there is an issue with automatically adding it then the oauth credentials will be displayed at the end of onboarding and can be [manually added to the configuration.](configuration.md#manually-adding-a-bot)
## Aardvark OAuth Helper
This method should only be used if you cannot use the [CM OAuth Helper method.](#cm-oauth-helper-recommended)
* Visit [https://not-an-aardvark.github.io/reddit-oauth-helper/](https://not-an-aardvark.github.io/reddit-oauth-helper/) and follow the instructions given.
* **Note:** You will need to update the **redirect uri** you set when [provisioning your reddit client.](/docs/operator/README.md#provisioning-a-reddit-client)
* **Note:** You will need to update the **redirect uri** you set when [provisioning your reddit client.](README.md#provisioning-a-reddit-client)
* Input your **Client ID** and **Client Secret** in the text boxes with those names.
* Choose scopes. **It is very important you check everything on this list or CM may not work correctly**
* edit
@@ -82,5 +89,5 @@ This method should only be used if you cannot use the [CM OAuth Helper method.](
* wikiread
* wikiedit (if you are using Toolbox User Notes)
* Click **Generate tokens**, you will get a popup asking you to approve access (or login) -- **the account you approve access with is the account that Bot will control.**
* After approving an **Access Token** and **Refresh Token** will be shown at the bottom of the page. Use these to [manually add a bot to your operator configuration.](/docs/operator/configuration.md#manually-adding-a-bot)
* After approving an **Access Token** and **Refresh Token** will be shown at the bottom of the page. Use these to [manually add a bot to your operator configuration.](configuration.md#manually-adding-a-bot)
* After adding the bot you will need to restart CM.

View File

@@ -1,3 +1,9 @@
---
parent: Operator
---
# Caching
# Table of Contents
* [Overview](#overview)

View File

@@ -1,3 +1,10 @@
---
parent: Operator
nav_order: 3
---
# Configuration
The **Operator** configuration refers to configuration used configure to the actual application/bot. This is different
from the **Subreddit** configuration that is defined in each Subreddit's wiki and determines the rules/actions for
activities the Bot runs on.
@@ -36,7 +43,7 @@ configuration.
Using a file has many benefits over using ARG or ENV:
* CM can automatically update your configuration
* CM can automatically add bots via the [CM OAuth Helper](/docs/operator/addingBot.md#cm-oauth-helper-recommended)
* CM can automatically add bots via the [CM OAuth Helper](addingBot.md#cm-oauth-helper-recommended)
* CM has a built-in configuration editor that can help you build and validate your configuration file
* File config is **required** if adding multiple bots to CM
@@ -44,8 +51,8 @@ Using a file has many benefits over using ARG or ENV:
By default CM will look for `config.yaml` or `config.json` in the `DATA_DIR` directory:
* [Local installation](/docs/operator/installation.md#locally) -- `DATA_DIR` is the root of your installation directory (same folder as `package.json`)
* [Docker](/docs/operator/installation.md#docker-recommended) -- `DATA_DIR` is at `/config` in the container
* [Local installation](installation.md#locally) -- `DATA_DIR` is the root of your installation directory (same folder as `package.json`)
* [Docker](installation.md#docker-recommended) -- `DATA_DIR` is at `/config` in the container
The `DATA_DIR` directory can be changed by passing `DATA_DIR` as an environmental variable EX `DATA_DIR=/path/to/directory`
@@ -65,7 +72,7 @@ One ContextMod instance can
However, the default configuration (using **ENV/ARG**) assumes your intention is to run one bot (one reddit account) on one CM instance without these additional features. This is to make this mode of operation easier for users with this intention.
To take advantage of this additional features you **must** use a **FILE** configuration. Learn about how this works and how to configure this scenario in the [Architecture Documentation.](/docs/serverClientArchitecture.md)
To take advantage of this additional features you **must** use a **FILE** configuration. Learn about how this works and how to configure this scenario in the [Architecture Documentation.](serverClientArchitecture.md)
## CLI Usage
@@ -79,7 +86,7 @@ node src/index.js run
Run `node src/index.js run help` to get a list of available command line options (denoted by **ARG** above):
<details>
<details markdown="block">
```
Usage: index [options] [command]
@@ -124,11 +131,11 @@ Options:
# Minimum Configuration
The minimum configuration required to run CM assumes you have no bots and want to use CM to [add your first bot.](/docs/operator/addingBot.md#cm-oauth-helper-recommended)
The minimum configuration required to run CM assumes you have no bots and want to use CM to [add your first bot.](addingBot.md#cm-oauth-helper-recommended)
You will need have this information available:
* From [provision a reddit client](/docs/operator/README.md#provisioning-a-reddit-client)
* From [provision a reddit client](README.md#provisioning-a-reddit-client)
* Client ID
* Client Secret
* Redirect URI (if different from default `http://localhost:8085/callback`)
@@ -136,6 +143,8 @@ You will need have this information available:
See the [**example minimum configuration** below.](#minimum-config)
This configuration can also be **generated** by CM if you start CM with **no configuration defined** and visit the web interface.
# Bots
Configured using the `bots` top-level property. Bot configuration can override and specify many more options than are available at the operator-level. Many of these can also set the defaults for each subreddit the bot runs:
@@ -151,7 +160,7 @@ Configured using the `bots` top-level property. Bot configuration can override a
## Adding A Bot
If you use the [CM OAuth Helper](/docs/operator/addingBot.md#cm-oauth-helper-recommended) and it works successfully then the configuration for the Bot will be automatically added.
If you use the [CM OAuth Helper](addingBot.md#cm-oauth-helper-recommended) and it works successfully then the configuration for the Bot will be automatically added.
### Manually Adding a Bot
@@ -164,7 +173,7 @@ Minimum information required for a valid bot:
* Refresh Token
* Access Token
<details>
<details markdown="block">
<summary>Example</summary>
```yaml
@@ -209,7 +218,7 @@ Below are examples of the minimum required config to run the application using a
Using **FILE**
<details>
<details markdown="block">
See [Specify File Location](#specify-file-location) for where this file would be located.
@@ -246,7 +255,7 @@ JSON (`config.json5`)
Using **ENV** (`.env`)
<details>
<details markdown="block">
```
OPERATOR=YourRedditUsername
@@ -259,7 +268,7 @@ REDIRECT_URI=http://localhost:8085/callback
Using **ARG**
<details>
<details markdown="block">
```
node src/index.js run --clientId=f4b4df1c7b2 --clientSecret=34v5q1c56ub --redirectUri=http://localhost:8085/callback
@@ -273,7 +282,7 @@ An example of using multiple configuration levels together IE all are provided t
**FILE**
<details>
<details markdown="block">
```json
{
@@ -294,7 +303,7 @@ logging:
**ENV** (`.env`)
<details>
<details markdown="block">
```
CLIENT_SECRET=34v5q1c56ub
@@ -306,7 +315,7 @@ PORT=9008
**ARG**
<details>
<details markdown="block">
```
node src/index.js run --subreddits=sub1 --clientId=34v5q1c56ub
@@ -326,9 +335,9 @@ log level: debug
## Configuring Client for Many Instances
See the [Architecture Docs](/docs/serverClientArchitecture.md) for more information.
See the [Architecture Docs](erverClientArchitecture.md) for more information.
<details>
<details markdown="block">
YAML
@@ -399,8 +408,8 @@ JSON
# Cache Configuration
See the [Cache Configuration](/docs/operator/caching.md) documentation.
See the [Cache Configuration](caching.md) documentation.
# Database Configuration
See the [Database Configuration](/docs/operator/database.md) documentation.
See the [Database Configuration](database.md) documentation.

View File

@@ -1,3 +1,9 @@
---
parent: Operator
---
# Database
# Overview
CM uses a database to store three types of data:
@@ -31,16 +37,16 @@ databaseConfig:
## SQLite
When using a [local installation](/docs/installation.md#locally) the default database is `sqljs`, which requires no binary dependencies. When using [docker](/docs/operator/installation.md#docker-recommended) the default is `better-sqlite3`.
When using a [local installation](installation.md#locally) the default database is `sqljs`, which requires no binary dependencies. When using [docker](installation.md#docker-recommended) the default is `better-sqlite3`.
**NOTE:** It is **NOT RECOMMENDED** to use `sqljs` in a production environment for performance reasons. You should at least switch to `better-sqlite3` or preferably MySql/Postgres.
* [`sqljs` connection options](https://typeorm.io/data-source-options#sqljs-data-source-options)
* [`better-sqlite3` connection options](https://typeorm.io/data-source-options#better-sqlite3-data-source-options)
For both sqlite types, if no database/location is specified, it will be created in the [`DATA_DIR` directory.](/docs/operator/configuration.md#specify-file-location)
For both sqlite types, if no database/location is specified, it will be created in the [`DATA_DIR` directory.](configuration.md#specify-file-location)
If CM detects it cannot **read and write** to the database files, or directory if no files exist, it will fallback to using an in-memory database that will be lost when CM restarts. If you have trouble with r/w permissions and are using docker make sure [file permissions are correct for your mounted volume.](/docs/operator/installation.md#linux-host)
If CM detects it cannot **read and write** to the database files, or directory if no files exist, it will fallback to using an in-memory database that will be lost when CM restarts. If you have trouble with r/w permissions and are using docker make sure [file permissions are correct for your mounted volume.](installation.md#linux-host)
## MySQL/MariaDB
@@ -95,7 +101,7 @@ The Retention Policy can be specified at operator level, bot, subreddit *overrid
operator:
name: u/MyRedditAccount
databaseConfig:
retention: '3 months' # each subreddit will retain 3 more of recorded events
retention: '3 months' # each subreddit will retain 3 months of recorded events
bots:
# all subreddits this bot moderates will have 3 month retention
- name: u/OneBotAccount
@@ -172,7 +178,7 @@ influxConfig:
A pre-built dashboard for [Grafana](https://grafana.com) can be imported to display overall metrics/stats using InfluxDB data.
![Grafana Dashboard](/docs/images/grafana.jpg)
![Grafana Dashboard](../images/grafana.jpg)
* Create a new Data Source using **InfluxDB** type
* Choose **Flux** for the **Query Language**
@@ -181,7 +187,7 @@ A pre-built dashboard for [Grafana](https://grafana.com) can be imported to disp
* Click **Save and test**
* Import Dashboard
* **Browse** the Dashboard pane
* Click **Import** and **upload** the [grafana dashboard json file](/docs/operator/grafana.json)
* Click **Import** and **upload** the [grafana dashboard json file](grafana.json)
* Chose the data source you created from the **InfluxDB CM** dropdown
* Click **Import**

View File

@@ -1,47 +1,48 @@
This getting started guide is for **Operators** -- that is, someone who wants to run the actual software for a ContentMod bot. If you are a **Moderator** check out the [moderator getting started](/docs/subreddit/gettingStarted.md) guide instead.
---
parent: Operator
nav_order: 1
---
# Getting Started
This getting started guide is for **Operators** -- that is, someone who wants to run the actual software for a ContentMod bot. If you are a **Moderator** check out the [moderator getting started](/docs/moderators/gettingStarted.md) guide instead.
# Table of Contents
* [Installation](#installation)
* [Create a Reddit Client](#create-a-reddit-client)
* [Create a Minimum Configuration](#create-a-minimum-configuration)
* [Local Installation](#local-installation)
* [Docker Installation](#docker-installation)
* [Start ContextMod](#start-contextmod)
* [Add a Bot to CM](#add-a-bot-to-cm)
* [Access The Dashboard](#access-the-dashboard)
* [What's Next?](#whats-next)
# Installation
Follow the [installation](/docs/operator/installation.md) documentation. It is recommended to use **Docker** since it is self-contained.
Follow the [installation](installation.md) documentation. It is recommended to use **Docker** since it is self-contained.
# Create a Reddit Client
[Create a reddit client](/docs/operator/README.md#provisioning-a-reddit-client)
[Create a reddit client](README.md#provisioning-a-reddit-client)
# Create a Minimum Configuration
# Start ContextMod
Using the information you received in the previous step [create a minimum file configuration](/docs/operator/configuration.md#minimum-configuration) save it as `config.yaml` somewhere.
Start CM using the example command from your [installation](#installation) and visit http://localhost:8085
# Start ContextMod With Configuration
The First Time Setup page will ask you to input:
## Local Installation
* Client ID (from [Create a Reddit Client](#create-a-reddit-client))
* Client Secret (from [Create a Reddit Client](#create-a-reddit-client))
* Operator -- this is the username of your main Reddit account.
If you [installed CM locally](/docs/installation.md#locally) move your configuration file `config.yaml` to the root of the project directory (where `package.json`) is located.
From the root directory run this command to start CM
```
node src/index.js run
```
## Docker Installation
If you [installed CM using Docker](/docs/installation.md#docker-recommended) make note of the directory you saved your minimum configuration to and substitute its full path for `host/path/folder` in the docker command show in the [docker install directions](/docs/operator/installation.md#docker-recommended)
**Write Config** and then restart CM. You have now created the [minimum configuration](configuration.md#minimum-configuration) required to run CM.
# Add A Bot to CM
Once CM is up and running use the [CM OAuth Helper](/docs/operator/addingBot.md#cm-oauth-helper-recommended) to add authorize and add a Bot to your CM instance.
You should automatically be directed to the [Bot Invite Helper](addingBot.md#cm-oauth-helper-recommended) used to authorize and add a Bot to your CM instance.
Follow the directions here and **create an Authorization Invite** at the bottom of the page.
Next, login to Reddit with the account you will be using as the Bot and then visit the **Authorization Invite** link you created. Follow the steps there to finish adding the Bot to your CM instance.
# Access The Dashboard
@@ -53,8 +54,8 @@ To monitor the behavior of bots running on your instance visit http://localhost:
# What's Next?
As an operator you should familiarize yourself with how the [operator configuration](/docs/operator/configuration.md) you made works. This will help you understand how to get the most of your CM instance by leveraging the [Cache](/docs/oeprator/caching.md) and [Database](/docs/operator/database.md) effectively as well as provide you will all possible options for configuring CM using the [schema.](https://json-schema.app/view/%23?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Fcontext-mod%2Fmaster%2Fsrc%2FSchema%2FOperatorConfig.json)
As an operator you should familiarize yourself with how the [operator configuration](configuration.md) you made works. This will help you understand how to get the most of your CM instance by leveraging the [Cache](caching.md) and [Database](database.md) effectively as well as provide you will all possible options for configuring CM using the [schema.](https://json-schema.app/view/%23?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Fcontext-mod%2Fmaster%2Fsrc%2FSchema%2FOperatorConfig.json)
If you are also the moderator of the subreddit the bot will be running you should check out the [moderator getting started guide.](/docs/subreddit/gettingStarted.md#setup-wiki-page)
If you are also the moderator of the subreddit the bot will be running you should check out the [moderator getting started guide.](../moderators/gettingStarted.md#setup-wiki-page)
You might also be interested in these [quick tips for using the web interface](/docs/webInterface.md)
You might also be interested in these [quick tips for using the web interface](../webInterface.md). Additionally, on the dashboard click the **Help** button at the top of the page to get a guided tour of the dashboard.

View File

@@ -1,3 +1,8 @@
---
parent: Operator
nav_order: 2
---
# Installation
In order to run a ContextMod instance you must first you must install it somewhere.
@@ -8,15 +13,19 @@ ContextMod can be run on almost any operating system but it is recommended to us
PROTIP: Using a container management tool like [Portainer.io CE](https://www.portainer.io/products/community-edition) will help with setup/configuration tremendously.
### [Dockerhub](https://hub.docker.com/r/foxxmd/context-mod)
Images available from these registeries:
An example of starting the container using the [minimum configuration](/docs/operator/configuration.md#minimum-config):
* [Dockerhub](https://hub.docker.com/r/foxxmd/context-mod) - `docker.io/foxxmd/context-mod`
* [GHCR](https://github.com/foxxmd/context-mod/pkgs/container/context-mod) - `ghcr.io/foxxmd/context-mod`
An example of starting the container using the [minimum configuration](configuration.md#minimum-config):
* Bind the directory where your config file, logs, and database are located on your host machine into the container's default `DATA_DIR` by using `-v /host/path/folder:/config`
* Note: **You must do this** or else your configuration will be lost next time your container is updated.
* Expose the web interface using the container port `8085`
```
docker run -d -v /host/path/folder:/config -p 8085:8085 foxxmd/context-mod
docker run -d -v /host/path/folder:/config -p 8085:8085 ghcr.io/foxxmd/context-mod:latest
```
The location of `DATA_DIR` in the container can be changed by passing it as an environmental variable EX `-e "DATA_DIR=/home/abc/config`
@@ -33,7 +42,35 @@ To get the UID and GID for the current user run these commands from a terminal:
* `id -g` -- prints GID
```
docker run -d -v /host/path/folder:/config -p 8085:8085 -e PUID=1000 -e PGID=1000 foxxmd/context-mod
docker run -d -v /host/path/folder:/config -p 8085:8085 -e PUID=1000 -e PGID=1000 ghcr.io/foxxmd/context-mod:latest
```
### Docker-Compose
The included [`docker-compose.yml`](/docker-compose.yml) provides production-ready dependencies for CM to use:
* [Redis](https://redis.io/) for caching
* [MariaDB](https://mariadb.org/) for database
* Optionally, [Influx/Grafana](database.md#influx) instances
#### Setup
The included `docker-compose.yml` file is written for **Docker Compose v2.**
For new installations copy [`config.yaml`](/docker/config/docker-compose/config.yaml) into a folder named `data` in the same folder `docker-compose.yml` will be run from. For users migrating their existing CM instances to docker-compose, copy your existing `config.yaml` into the same `data` folder.
Read through the comments in both `docker-compose.yml` and `config.yaml` and makes changes to any relevant settings (passwords, usernames, etc...). Ensure that any settings used in both files (EX mariaDB passwords) match.
To build and start CM:
```bash
docker compose up -d
```
To include Grafana/Influx dependencies run:
```bash
docker compose --profile full up -d
```
## Locally
@@ -53,7 +90,7 @@ npm install
tsc -p .
```
An example of running CM using the [minimum configuration](/docs/operator/configuration.md#minimum-config) with a [configuration file](/docs/operator/configuration.md#file-configuration-recommended):
An example of running CM using the [minimum configuration](configuration.md#minimum-config) with a [configuration file](configuration.md#file-configuration-recommended):
```bash
node src/index.js run

View File

@@ -1,3 +1,9 @@
---
parent: Operator
---
# Architecture
# Overview
ContextMod's high-level functionality is separated into two **independently run** applications.

View File

@@ -1,3 +1,10 @@
---
has_children: true
nav_order: 5
---
# Subreddit Configuration
High level overviews, important features of, and example usage for significant components in a subreddit's configuration are found here.
This list is not exhaustive. [For complete documentation on a subreddit's configuration consult the schema.](https://json-schema.app/view/%23?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fmaster%2Fsrc%2FSchema%2FApp.json)
@@ -22,6 +29,7 @@ This list is not exhaustive. [For complete documentation on a subreddit's config
* [Regex](#regex)
* [Repost](#repost)
* [Sentiment Analysis](#sentiment-analysis)
* [Toxic Content Prediction](#moderatehatespeechcom-predictions)
* [Rule Sets](#rule-sets)
* [Actions](#actions)
* [Named Actions](#named-actions)
@@ -29,6 +37,7 @@ This list is not exhaustive. [For complete documentation on a subreddit's config
* [List of Actions](#list-of-actions)
* [Approve](#approve)
* [Ban](#ban)
* [Submission](#submission)
* [Comment](#comment)
* [Contributor (Add/Remove)](#contributor)
* [Dispatch/Delay](#dispatch)
@@ -43,13 +52,6 @@ This list is not exhaustive. [For complete documentation on a subreddit's config
* [Toolbox UserNote](#usernote)
* [Mod Note](#mod-note)
* [Filters](#filters)
* [Filter Types](#filter-types)
* [Author Filter](#author-filter)
* [Mod Notes/Actions](#mod-actionsnotes-filter)
* [Toolbox UserNotes](#toolbox-usernotes-filter)
* [Item Filter](#item-filter)
* [Subreddit Filter](#subreddit-filter)
* [Named Filters](#named-filters)
* [Common Patterns](#common-patterns)
* [Conditions](#conditions)
* [Activities `window`](#activities-window)
@@ -68,11 +70,12 @@ This list is not exhaustive. [For complete documentation on a subreddit's config
* [Rule Order](#rule-order)
* [Configuration Re-use and Caching](#configuration-re-use-and-caching)
* [Partial Configurations](#partial-configurations)
* [Sharing Configs Between Subreddits](#sharing-full-configs-as-runs)
* [Subreddit-ready examples](#subreddit-ready-examples)
# Runs
A **Run** is made up of a set of [**Checks**](#checks) that represent a group of related behaviors the bot should check for or perform. Checks within a Run are processed in the order they are listed. Refer to the [How It Works](/docs/README.md#how-it-works) section to see how Runs fit into CM's lifecycle.
A **Run** is made up of a set of [**Checks**](#checks) that represent a group of related behaviors the bot should check for or perform. Checks within a Run are processed in the order they are listed. Refer to the [How It Works](../README.md#how-it-works) section to see how Runs fit into CM's lifecycle.
**Runs** are the largest unit of behavior in a subreddit's configuration and are defined at the top level of the configuration like so:
@@ -132,13 +135,13 @@ A **Check** is a set of:
* Zero or more [**Rules**](#rules) that define what conditions should **trigger** this Check.
* Zero or more [**Actions**](#actions) that define what the bot should do once the Check is **triggered**.
Refer to the [How It Works](/docs/README.md#how-it-works) section to see how Checks fit into CM's lifecycle.
Refer to the [How It Works](../README.md#how-it-works) section to see how Checks fit into CM's lifecycle.
* If a Check has no Rules and passes any [Filters](#filters) it is automatically triggered
* If a Check is triggered and has no Actions it is only [recorded](#recording-options)
* **Checks must have explicitly defined:**
* **name**
* **kind** -- what type of [Activity](/docs/README.md#activity) (`submission` or `comment`) it should process
* **kind** -- what type of [Activity](../README.md#activity) (`submission` or `comment`) it should process
```yaml
runs:
@@ -214,11 +217,11 @@ This enables a user to arbitrarily configure how CM responds to the triggering (
Each Check will **always** have these properties defined -- either explicitly or passed down as defaults from a [Run](#flow-control-defaults-using-runs), [Subreddit](#filter-defaults), or Operator configuration.
Refer to the main [**Flow Control** documentation](/docs/subreddit/components/advancedConcepts/flowControl.md) for an in-depth explanation and all possible options.
Refer to the main [**Flow Control** documentation](advancedConcepts/flowControl.md) for an in-depth explanation and all possible options.
## Recording Options
`postFail` and `postTrigger` also enable specifying if/how an [Event](/docs/README.md#event) is recorded. Valid options for recording:
`postFail` and `postTrigger` also enable specifying if/how an [Event](../README.md#event) is recorded. Valid options for recording:
* `false` -- do not record this Event
* `true` -- record Event to all available outputs
@@ -248,7 +251,7 @@ When an Activity has finished being processed CM will aggregate all Recording Op
# Rules
A **Rule** is some set of **criteria** (conditions) that are tested against an [Activity](/docs/README.md#activity), a User, or a User's history. A Rule is considered **triggered** when the **criteria** for that rule are found to be **true** for whatever is being tested against.
A **Rule** is some set of **criteria** (conditions) that are tested against an [Activity](../README.md#activity), a User, or a User's history. A Rule is considered **triggered** when the **criteria** for that rule are found to be **true** for whatever is being tested against.
Rules must have a `kind` that identifies what kind of Rule they are.
@@ -291,13 +294,13 @@ runs:
Named Rules are essential building blocks of a readable and effective configuration. If you find yourself repeating the same Rule many times it's a sign you should give it a name and replace it's usage with references to it.
See **Rule Name Reuse Examples [YAML](/docs/subreddit/components/advancedConcepts/ruleNameReuse.yaml) | [JSON](/docs/subreddit/components/advancedConcepts/ruleNameReuse.json5)**
See **Rule Name Reuse Examples [YAML](advancedConcepts/ruleNameReuse.yaml) | [JSON](advancedConcepts/ruleNameReuse.json5)**
## List of Rules
### Attribution
[**Full Documentation**](/docs/subreddit/components/attribution)
[**Full Documentation**](in-depth/attribution)
The **Attribution** rule will aggregate an Author's content Attributions (youtube channels, twitter, website domains, etc.) and can check on their totals or percentages of all Activities over a time period:
@@ -308,7 +311,7 @@ The **Attribution** rule will aggregate an Author's content Attributions (youtub
### Recent Activity
[**Full Documentation**](/docs/subreddit/components/recentActivity)
[**Full Documentation**](in-depth/recentActivity)
Given a list subreddit criteria, the **Recent Activity** rule finds Activities matching those criteria in the Author's history over [window](#activities-window) and then allows for comparing different facets of the results:
@@ -320,14 +323,14 @@ The above can also be expressed as a percentage of all activities found, instead
The search can also be modified in a number of ways:
* Filter found activities using an [Item Filter](#item-filter)
* Filter found activities using an [Item Filter](in-depth/filters#item-filter)
* Only return activities that match the Activity from the Event being processed
* Using [image detection](/docs/imageComparison.md) (pixel or perceptual hash matching)
* Using [image detection](imageComparison.md) (pixel or perceptual hash matching)
* Only return certain types of activities (only submission or only comments)
### Repeat Activity
[**Full Documentation**](/docs/subreddit/components/repeatActivity)
[**Full Documentation**](in-depth/repeatActivity)
The **Repeat Activity** rule will check for patterns of repetition in an Author's Activity history over a [window](#activities-window). When comparing submissions it checks a composite of the submissions' title and content.
@@ -342,7 +345,7 @@ Some of the ways the rule can be modified:
### History
[**Full Documentation**](/docs/subreddit/components/history)
[**Full Documentation**](in-depth/history)
The **History** rule can check an Author's submission/comment statistics over a time period:
@@ -352,30 +355,36 @@ The **History** rule can check an Author's submission/comment statistics over a
### Author
[**Full Documentation**](/docs/subreddit/components/author)
[**Full Documentation**](in-depth/author)
The **Author** rule behaves the same as the [Author Filter](#author-filter). It can be used when you want to test Author state alongside other rules to create more complex behavior than would be possible by only applying to individual Rules or an entire check.
The **Author** rule behaves the same as the [Author Filter](in-depth/filters#author-filter). It can be used when you want to test Author state alongside other rules to create more complex behavior than would be possible by only applying to individual Rules or an entire check.
### Regex
[**Full Documentation**](/docs/subreddit/components/regex)
[**Full Documentation**](in-depth/regex)
The **Regex** rule matches on text content from an Activity in the same way automod uses regex. However, it can also be used to match on content from the Author's Activity history over a [window](#activities-window).
### Repost
[**Full Documentation**](/docs/subreddit/components/repost)
[**Full Documentation**](in-depth/repost)
The **Repost** rule is used to find reposts for both **Submissions** and **Comments**, depending on what type of **Check** it is used on.
This rule is for searching **all of Reddit** for reposts, as opposed to just the history of the Author of the Activity being checked. If you only want to check for reposts by the Author of the Activity being checked you should use the [Repeat Activity](/docs/subreddit/components/repeatActivity) rule.
This rule is for searching **all of Reddit** for reposts, as opposed to just the history of the Author of the Activity being checked. If you only want to check for reposts by the Author of the Activity being checked you should use the [Repeat Activity](repeatActivity) rule.
### Sentiment Analysis
[**Full Documentation**](/docs/subreddit/components/sentiment)
[**Full Documentation**](in-depth/sentiment)
The **Sentiment Rule** is used to determine the overall emotional intent (negative, neutral, positive) of a Submission or Comment by analyzing the actual text content of the Activity.
### ModerateHateSpeech.com Predictions
[**Full Documentation**](in-depth/mhs)
ContextMod integrates with [moderatehatespeech.com](https://moderatehatespeech.com/) (MHS) [toxic content machine learning model](https://moderatehatespeech.com/framework/) through their API. This rule sends an Activity's content (title or body) to MHS which returns a prediction on whether the content is toxic and actionable by a moderator. Their model is [specifically trained for reddit content.](https://www.reddit.com/r/redditdev/comments/xdscbo/updated_bot_backed_by_moderationoriented_ml_for/)
# Rule Sets
The `rules` list on a `Check` can contain both `Rule` objects and `RuleSet` objects.
@@ -411,7 +420,7 @@ runs:
...
```
See **ruleSets [YAML](/docs/subreddit/components/advancedConcepts/ruleSets.yaml) | [JSON](/docs/subreddit/components/advancedConcepts/ruleSets.json5)** for a complete example as well as consulting the [schema](https://json-schema.app/view/%23%2Fdefinitions%2FRuleSetJson?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Fcontext-mod%2Fmaster%2Fsrc%2FSchema%2FApp.json).
See **ruleSets [YAML](advancedConcepts/ruleSets.yaml) | [JSON](advancedConcepts/ruleSets.json5)** for a complete example as well as consulting the [schema](https://json-schema.app/view/%23%2Fdefinitions%2FRuleSetJson?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Fcontext-mod%2Fmaster%2Fsrc%2FSchema%2FApp.json).
# Actions
@@ -423,7 +432,7 @@ Actions are performed in the order they are listed in the **Check.**
## Named Actions
**Named Actions** work the same as [**Named Rules**](#named-rules) and [**Named Filters:**](#named-filters)
**Named Actions** work the same as [**Named Rules**](#named-rules) and [**Named Filters:**](in-depth/filters#named-filters)
Actions may be given a `name`. If an Action is named it can **re-used anywhere in the configuration regardless of location.** This is done by:
@@ -455,7 +464,7 @@ runs:
Actions that can submit text (Report, Comment, UserNote) will have their `content` values run through a [Mustache Template](https://mustache.github.io/). This means you can insert data generated by Rules into your text before the Action is performed.
[**Action Templating Documentation**](/docs/subreddit/actionTemplating.md)
[**Action Templating Documentation**](actionTemplating.md)
## List of Actions
@@ -494,11 +503,30 @@ actions:
### Comment
Reply to the Activity being processed with a comment. [Schema Documentation](https://json-schema.app/view/%23/%23%2Fdefinitions%2FSubmissionCheckJson/%23%2Fdefinitions%2FCommentActionJson?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fmaster%2Fsrc%2FSchema%2FApp.json)
Reply to an Activity with a comment. [Schema Documentation](https://json-schema.app/view/%23/%23%2Fdefinitions%2FSubmissionCheckJson/%23%2Fdefinitions%2FCommentActionJson?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fmaster%2Fsrc%2FSchema%2FApp.json)
* If the Activity is a Submission the comment is a top-level reply
* If the Activity is a Comment the comment is a child reply
#### Templating
`content` can be [templated](#templating) and use [URL Tokens](#url-tokens)
#### Targets
Optionally, specify the Activity CM should reply to. **When not specified CM replies to the Activity being processed using `self`**
Valid values: `self`, `parent`, or a Reddit permalink.
`self` and `parent` are special targets that are relative to the Activity being processed:
* When the Activity being processed is a **Submission** => `parent` logs a warning and does nothing
* When the Activity being processed is a **Comment**
* `self` => reply to Comment
* `parent` => make a top-level Comment in the **Submission** the Comment belong to
If target is not self/parent then CM assumes the value is a **reddit permalink** and will attempt to make a Comment to that Activity
```yaml
actions:
- kind: comment
@@ -506,7 +534,90 @@ actions:
distinguish: boolean # distinguish as a mod
sticky: boolean # sticky comment
lock: boolean # lock the comment after creation
targets: string # 'self' or 'parent' or 'https://reddit.com/r/someSubreddit/21nfdi....'
```
### Comment As Subreddit
ContextMod can comment [as the subreddit](https://www.reddit.com/r/modnews/comments/wpy5c8/announcing_remove_as_a_subreddit/) using the `/u/subreddit-ModTeam` account with some restrictions:
* The activity being replied to must ALREADY BE REMOVED.
* You can use the [Remove Action](#remove) beforehand to ensure this is the case.
* The created comment will always be stickied and distinguished
Usage:
```yaml
actions:
- kind: comment
asModTeam: true
content: string # required, the content of the comment
lock: boolean # lock the comment after creation
targets: string # 'self' or 'parent' or 'https://reddit.com/r/someSubreddit/21nfdi....'
```
### Submission
Create a Submission [Schema Documentation](https://json-schema.app/view/%23/%23%2Fdefinitions%2FSubmissionCheckJson/%23%2Fdefinitions%2FSubmissionActionJson?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fmaster%2Fsrc%2FSchema%2FApp.json)
The Submission type, Link or Self-Post, is determined based on the presence of `url` in the action's configuration.
```yaml
actions:
- kind: submission
title: string # required, the title of the submission. can be templated.
content: string # the body of the submission. can be templated
url: string # if specified the submission will be a Link Submission. can be templated
distinguish: boolean # distinguish as a mod
sticky: boolean # sticky comment
lock: boolean # lock the comment after creation
nsfw: boolean # mark submission as NSFW
spoiler: boolean # mark submission as a spoiler
flairId: string # flair template id for submission
flairText: string # flair text for submission
targets: string # 'self' or a subreddit name IE mealtimevideos
```
#### Templating
`content`,`url`, and `title` can be [templated](#templating) and use [URL Tokens](#url-tokens)
TIP: To create a Link Submission pointing to the Activity currently being processed use
```yaml
actions:
- kind: submission
url: {{item.permalink}}
# ...
```
#### Targets
Optionally, specify the Subreddit the Submission should be made in. **When not specified CM uses `self`**
Valid values: `self` or Subreddit Name
* `self` => (**Default**) Create Submission in the same Subreddit of the Activity being processed
* Subreddit Name => Create Submission in given subreddit IE `mealtimevideos`
* Your bot must be able to access and be able to post in the given subreddit
Example:
```yaml
actions:
- kind: comment
targets: mealtimevideos
```
To post to multiple subreddits use a list:
```yaml
actions:
- kind: comment
targets:
- self
- mealtimevideos
- anotherSubreddit
```
### Contributor
@@ -608,15 +719,16 @@ Some other things to note:
* If the `to` property is not specified then the message is sent to the Author of the Activity being processed
* `to` may be a **User** (u/aUser) or a **Subreddit** (r/aSubreddit)
* `to` **cannot** be a Subreddit when `asSubreddit: true` -- IE cannot send subreddit-to-subreddit messages
* `content` can be [templated](#templating) and use [URL Tokens](#url-tokens)
* TIP: `to` can be templated -- to send a message to the subreddit the Activity being processed is in use `'r/{{item.subreddit}}'`
* `content` and `title` can be [templated](#templating) and use [URL Tokens](#url-tokens)
```yaml
actions:
- kind: message
asSubreddit: true
content: 'A message sent as the subreddit'
title: 'Title of the message'
to: 'u/aUser' # do not specify 'to' in order default to sending to Author of Activity being processed
content: 'A message sent as the subreddit' # can be templated
title: 'Title of the message' # can be templated
to: 'u/aUser' # do not specify 'to' in order default to sending to Author of Activity being processed. Can also be templated
```
### Remove
@@ -624,7 +736,7 @@ actions:
Remove the Activity being processed. [Schema Documentation](https://json-schema.app/view/%23/%23%2Fdefinitions%2FSubmissionCheckJson/%23%2Fdefinitions%2FRemoveActionJson?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fedge%2Fsrc%2FSchema%2FApp.json)
* **note** can be [templated](#templating)
* **reasonId** IDs can be found in the [editor](/docs/webInterface.md) using the **Removal Reasons** popup
* **reasonId** IDs can be found in the [editor](../../webInterface.md) using the **Removal Reasons** popup
If neither note nor reasonId are included then no removal reason is added.
@@ -652,7 +764,7 @@ actions:
Add a Toolbox User Note to the Author of the Activity. [Schema Documentation](https://json-schema.app/view/%23/%23%2Fdefinitions%2FSubmissionCheckJson/%23%2Fdefinitions%2FUserNoteActionJson?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fedge%2Fsrc%2FSchema%2FApp.json)
Your subreddit must have [Toolbox UserNotes](/docs/subreddit/components/userNotes) enabled for this action to work.
Your subreddit must have [Toolbox UserNotes](in-depth/userNotes) enabled for this action to work.
* `type` is required
* `content` can be [templated](#templating) and use [URL Tokens](#url-tokens)
@@ -662,12 +774,12 @@ actions:
- kind: usernote
type: spamwarn
content: 'Usernote message'
allowDuplicate: boolean # if false then the usernote will not be added if the same note appears for this activity
existingNoteCheck: boolean # if true (default) then the usernote will not be added if the same note appears for this activity
```
### Mod Note
[**Full Documentation**](/docs/subreddit/components/modActions/README.md#mod-note-action)
[**Full Documentation**](in-depth/modActions/README.md#mod-note-action)
Add a [Mod Note](https://www.reddit.com/r/modnews/comments/t8vafc/announcing_mod_notes/) for the Author of the Activity.
@@ -687,6 +799,7 @@ actions:
type: SPAM_WATCH
content: 'a note only mods can see message' # optional
referenceActivity: boolean # if true the Note will be linked to the Activity being processed
existingNoteCheck: boolean # if true (default) then the note will not be added if the same note appears for this activity
```
# Filters
@@ -695,133 +808,17 @@ actions:
* **Runs, Checks, Rules, and Actions** can **all** have Filters
* Filters test against the **current state** of the Activity (or it's Author) being processed, rather than looking at history/context/etc...
* CM supports filters for:
* [Author](in-depth/filters#author-filter) - age, verified email, profile description, flair...
* [Item (Submission/Comment)](in-depth/filters#item-filter) - sticked, # of reports, removed, flair, score...
* [Subreddit](in-depth/filters#subreddit-filter) - name, nsfw, quarantined...
* [Toolbox Usernotes](in-depth/filters#toolbox-usernotes-filter)
* [Mod Notes](in-depth/filters#mod-actionsnotes-filter)
* Filter test results only determine if the Run, Check, Rule, or Action **should run** -- rather than triggering it
* When the filter test **passes** the thing being tested continues to process as usual
* When the filter test **fails** the thing being tested **fails**.
A Filter has these properties:
* `include` -- An optional list of Filter Criteria. If **any** passes the filter passes.
* `exclude` -- An optional list of Filter Criteria. All **must NOT** pass for the filter to pass. Ignored if `include` is present.
* `excludeCondition` -- A [condition](#conditions) that determines how the list of Filter Criteria are tested together
## Filter Criteria
A **criteria** is some property of a thing can be tested, and what the expected outcome is EX
`age: '> 2 months'` => Author is older than 2 months
**Filter Criteria** is one of more **criteria** combined together to form a set of criteria that must all be true together for the Filter Criteria to be true EX
```yaml
age: '> 2 months'
verified: true
```
The above Filter Criteria is true if the Author's account is older than 2 months AND they have a verified email
### Filter Shapes
Generically, a "full" Filter looks like this:
```yaml
include: #optional
- name: AFilterCriteria
criteria:
...
... #one or more filter criteria
exclude: #optional
... # one or more filter criteria
excludeCondition: OR or AND
```
But for convenience a Filter's shape can be simplified with a few assumptions
#### Simple Object
When a Filter is an object, the object is assumed to be a Filter Criteria which is used in `include`
```yaml
itemIs:
approved: false
```
#### Simple List
When a Filter is a list, the list is assumed to be a list of Filter Criteria and used in `include`
```yaml
itemIs:
- approved: false
filtered: false
- is_self: true
```
## Filter Types
There are two types of Filter. Both types have the same "shape" in the configuration with the differences between them being:
* what they are testing on
* what criteria are available to test
### Author Filter
Test the Author of an Activity. See [Schema documentation](https://json-schema.app/view/%23%2Fdefinitions%2FAuthorCriteria?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fedge%2Fsrc%2FSchema%2FApp.json) for all possible Author Criteria
#### Mod Actions/Notes Filter
See [Mod Actions/Notes](/docs/subreddit/components/modActions/README.md#mod-action-filter) documentation.
#### Toolbox UserNotes Filter
See [UserNotes](/docs/subreddit/components/userNotes/README.md) documentation
### Item Filter
Test for properties of an Activity:
* [Comment Criteria](https://json-schema.app/view/%23%2Fdefinitions%2FCommentState?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fedge%2Fsrc%2FSchema%2FApp.json)
* [Submission Criteria](https://json-schema.app/view/%23%2Fdefinitions%2FSubmissionState?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fedge%2Fsrc%2FSchema%2FApp.json)
### Subreddit Filter
Test for properties of the Subreddit an Activity belongs to. See [Schema documentation](https://json-schema.app/view/%23%2Fdefinitions%2FSubredditCriteria?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fedge%2Fsrc%2FSchema%2FApp.json)
## Named Filters
**Named Filters** work the same as [**Named Rules**](#named-rules) and [**Named Actions:**](#named-actions)
**Filter Criteria** may be given a `name`. A named **Filter Criteria** can **re-used anywhere in the configuration regardless of location.** This is done by:
* specifying a name on a **Filter Criteria** **once** EX: `name: MyFitlerCriteria`
* using the Filter Criteria's name in place of a Filter Criteria object
```yaml
runs:
- name: MyFirstRun
checks:
- name: MyFirstCheck
kind: submission
itemIs:
- MyFilterCriteria
rules:
...
actions:
...
- name: MySecondCheck
kind: submission
itemIs:
include:
- name: MyFilterCriteria
criteria:
approved: false
rules:
...
actions:
...
```
[**Refer to the full Filter documentation for more**](in-depth/filters)
# Common Patterns
@@ -861,7 +858,7 @@ These conditions can be combined together to evaluate to either true or false us
Most **Rules** have a `window` property somewhere within their configuration. This property defines the range of **Activities** (submission and/or comments) that should be retrieved for checking the criteria of the Rule.
[Full Activities `window` documentation](/docs/subreddit/activitiesWindow.md)
[Full Activities `window` documentation](activitiesWindow.md)
## URL Tokens
@@ -923,7 +920,7 @@ Some criteria accept an optional **duration** to compare against:
The duration value compares a time range from **now** to `duration value` time in the past.
Refer to [duration values in activity window documentation](/docs/subreddit/activitiesWindow.md#duration-values) as well as the individual rule/criteria schema to see what this duration is comparing against.
Refer to [duration values in activity window documentation](activitiesWindow.md#duration) as well as the individual rule/criteria schema to see what this duration is comparing against.
## Filter Defaults
@@ -957,7 +954,7 @@ In other words -- Checks will not run if the Author of the Activity being proces
## Flow Control Defaults
See [Flow Control Documentation](/docs/subreddit/components/advancedConcepts/flowControl.md#default-behaviors)
See [Flow Control Documentation](advancedConcepts/flowControl.md#default-behaviors)
# Subreddit-Level Configuration
@@ -967,7 +964,7 @@ See [Filter Defaults](#filter-defaults) and [Flow Control Defaults](#flow-contro
## Polling
**Polling** is how ContextMod creates [Events](/docs/README.md#event) from new Activities in a Subreddit. CM monitors one or more polling sources and processes any new Activities it discovers.
**Polling** is how ContextMod creates [Events](../README.md#event) from new Activities in a Subreddit. CM monitors one or more polling sources and processes any new Activities it discovers.
### Polling Sources
@@ -1099,7 +1096,7 @@ Re-use will result in less API calls and faster Check times.
PROTIP: You can monitor the re-use of cache in the `Cache` section of your subreddit on the web interface. See the tooltips in that section for a better breakdown of cache statistics.
[Learn more about how Caching works](/docs/operator/caching.md)
[Learn more about how Caching works](../operator/caching.md)
## Partial Configurations
@@ -1154,6 +1151,49 @@ The object contains:
* `path` -- REQUIRED string following rules above
* `ttl` -- OPTIONAL, number of seconds to cache the URL result. Defaults to `WikiTTL`
### Sharing Full Configs as Runs
If the Fragment fetched by CM is a "full config" (including `runs`, `polling`, etc...) that could be used as a valid config for another subreddit then CM will extract and use the **Runs** from that config.
**However, the config must also explicitly allow access for use as a Fragment.** This is to prevent subreddits that share a Bot account from accidentally (or intentionally) gaining access to another subreddit's config with permissions.
#### Sharing
The config that will be shared (accessed at `wiki:botconfig/contextbot|SharingSubreddit`) must have the `sharing` property defined at its top-level. If `sharing` is not defined access will be denied for all subreddits.
```yaml
sharing: false # deny access to all subreddits (default when sharing is not defined)
polling:
- newComm
runs:
# ...
```
```yaml
sharing: true # any subreddit can use this config (reddit account must also be able to access wiki page)
```
```yaml
# when a list is given all subreddit names that match any from the list are ALLOWED to access the config
# list can be regular expressions or case-insensitive strings
sharing:
- mealtimevideos
- videos
- '/Ask.*/i'
```
```yaml
# if `exclude` is used then any subreddit name that is NOT on this list can access the config
# list can be regular expressions or case-insensitive strings
sharing:
exclude:
- mealtimevideos
- videos
- '/Ask.*/i'
```
#### Examples
**Replacing A Rule with a URL Fragment**
@@ -1176,7 +1216,7 @@ runs:
subreddits:
- MyBadSubreddit
window: 7 days
actions:
actions:
- kind: report
content: 'uses freekarma subreddits and bad subreddits'
```
@@ -1211,6 +1251,33 @@ runs:
content: 'uses freekarma subreddits'
```
**Using Another Subreddit's Config**
```yaml
runs:
- `wiki:botconfig/contextbot|SharingSubreddit`
- name: MySubredditSpecificRun
checks:
- name: Free Karma Alert
description: Check if author has posted in 'freekarma' subreddits
kind: submission
rules:
- 'wiki:freeKarmaFrag'
actions:
- kind: report
content: 'uses freekarma subreddits'
```
In `r/SharingSubreddit`:
```yaml
sharing: true
runs:
- name: ARun
# ...
```
# Subreddit-Ready Examples
Refer to the [Subreddit-Ready Examples](/docs/subreddit/components/subredditReady) section to find ready-to-use configurations for common scenarios (spam, freekarma blocking, etc...). This is also a good place to familiarize yourself with what complete configurations look like.
Refer to the [Subreddit Cookbook Examples](cookbook) section to find ready-to-use configurations for common scenarios (spam, freekarma blocking, etc...). This is also a good place to familiarize yourself with what complete configurations look like.

View File

@@ -0,0 +1,204 @@
---
parent: Subreddit Configuration
---
# Action Templating
Actions that can submit text (Report, Comment, UserNote, Message, Ban, Submission) will have their `content` values run through a [Mustache Template](https://mustache.github.io/). This means you can insert data generated by Rules into your text before the Action is performed.
See here for a [cheatsheet](https://gist.github.com/FoxxMD/d365707cf99fdb526a504b8b833a5b78) and [here](https://www.tsmean.com/articles/mustache/the-ultimate-mustache-tutorial/) for a more thorough tutorial.
# Template Data
Some data can always be accessed at the top-level. Example
```
This action was run from {{manager}} in Check {{check}}.
The bot intro post is {{botLink}}
Message the moderators of this subreddit using this [compose link]({{modmailLink}})
```
| Name | Description | Example |
|---------------|---------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
| `manager` | The name of the subreddit the bot is running in | mealtimevideos |
| `check` | The name of the Check that was triggered | myCheck |
| `botLink` | A link to the bot introduction | https://www.reddit.com/r/ContextModBot/comments/otz396/introduction_to_contextmodbot |
| `modmailLink` | A link that opens reddit's DM compose with the subject line as the Activity being processed | https://www.reddit.com/message/compose?to=/r/mealtimevideos&message=https://www.reddit.com/r/ContextModBot/comments/otz396/introduction_to_contextmodbot |
## Activity Data
**Activity data can be accessed using the `item` variable.** Example
```
This activity is a {{item.kind}} with {{item.votes}} votes, created {{item.age}} ago.
```
Produces:
> This activity is a submission with 10 votes created 5 minutes ago.
### Common
All Actions with `content` have access to this data:
| Name | Description | Example |
|--------------|-----------------------------------------------------------------------------------------------------|----------------------------------------------------------|
| `kind` | The Activity type (submission or comment) | submission |
| `author` | Name of the Author of the Activity being processed | FoxxMD |
| `permalink` | URL to the Activity | https://reddit.com/r/mySuibreddit/comments/ab23f/my_post |
| `votes` | Number of upvotes | 69 |
| `age` | The age of the Activity in a [human friendly format](https://day.js.org/docs/en/durations/humanize) | 5 minutes |
| `subreddit` | The name of the subreddit the Activity is from | mealtimevideos |
| `id` | The `Reddit Thing` ID for the Activity | t3_0tin1 |
| `title` | As comments => the body of the comment. As Submission => title | Test post please ignore |
| `shortTitle` | The same as `title` but truncated to 15 characters | test post pleas... |
#### Common Author
Additionally, `author` has these properties accessible:
| Name | Description | Example |
|----------------|-------------------------------------|----------|
| `age` | (Approximate) Age of account | 3 months |
| `linkKarma` | Amount of link karma | 10 |
| `commentKarma` | Amount of comment karma | 3 |
| `totalKarma` | Combined link+comment karma | 13 |
| `verified` | Does account have a verified email? | true |
NOTE: Accessing these properties may require an additional API call so use sparingly on high-volume comments
##### Example Usage
```
The user {{item.author}} has been a redditor for {{item.author.age}}
```
Produces:
> The user FoxxMD has been a redditor for 3 months
### Submissions
If the **Activity** is a Submission these additional properties are accessible:
| Name | Description | Example |
|---------------|-----------------------------------------------------------------|-------------------------|
| `upvoteRatio` | The upvote ratio | 100% |
| `nsfw` | If the submission is marked as NSFW | true |
| `spoiler` | If the submission is marked as a spoiler | true |
| `url` | If the submission was a link then this is the URL for that link | http://example.com |
| `title` | The title of the submission | Test post please ignore |
### Comments
If the **Activity** is a Comment these additional properties are accessible:
| Name | Description | Example |
|------|--------------------------------------------------------------|---------|
| `op` | If the Author is the OP of the Submission this comment is in | true |
### Moderator
If the **Activity** occurred in a Subreddit the Bot moderates these properties are accessible:
| Name | Description | Example |
|---------------|-------------------------------------|---------|
| `reports` | The number of reports recieved | 1 |
| `modReports` | The number of reports by moderators | 1 |
| `userReports` | The number of reports by users | 1 |
## Rule Data
### Summary
A summary of what rules were processed and which were triggered, with results, is available using the `ruleSummary` variable. Example:
```
A summary of rules processed for this activity:
{{ruleSummary}}
```
Would produce:
> A summary of rules processed for this activity:
>
> * namedRegexRule - ✘
> * nameAttributionRule - ✓ - 1 Attribution(s) met the threshold of < 20%, with 1 (3%) of 32 Total -- window: 6 months
> * noXPost ✓ - ✓ 1 of 1 unique items repeated <= 3 times, largest repeat: 1
### Individual
Individual **Rules** can be accessed using the name of the rule, **lower-cased, with all spaces/dashes/underscores.** Example:
```
Submission was repeated {{rules.noxpost.largestRepeat}} times
```
Produces
> Submission was repeated 7 times
## Action Data
### Summary
A summary of what actions have already been run **when the template is rendered** is available using the `actionSummary` variable. It is therefore important that the Action you want to produce the summary is run **after** any other Actions you want to get a summary for.
Example:
```
A summary of actions processed for this activity, so far:
{{actionSummary}}
```
Would produce:
> A summary of actions processed for this activity, so far:
>
> * approve - ✘ - Item is already approved??
> * lock - ✓
> * modnote - ✓ - (SOLID_CONTRIBUTOR) User is good
### Individual
Individual **Actions** can be accessed using the name of the action, **lower-cased, with all spaces/dashes/underscores.** Example:
```
User was banned for {{actions.exampleban.duration}} for {{actions.exampleban.reason}}
```
Produces
> User was banned for 4 days for toxic behavior
# Quick Templating Tutorial
As a quick example for how you will most likely be using templating -- wrapping a variable in curly brackets, `{{variable}}`, will cause the variable value to be rendered instead of the brackets:
```
myVariable = 50;
myOtherVariable = "a text fragment"
template = "This is my template, the variable is {{myVariable}}, my other variable is {{myOtherVariable}}, and that's it!";
console.log(Mustache.render(template, {myVariable});
// will render...
"This is my template, the variable is 50, my other variable is a text fragment, and that's it!";
```
**Note: When accessing an object or its properties you must use dot notation**
```
const item = {
aProperty: 'something',
anotherObject: {
bProperty: 'something else'
}
}
const content = "My content will render the property {{item.aProperty}} like this, and another nested property {{item.anotherObject.bProperty}} like this."
```

View File

@@ -1,3 +1,9 @@
---
parent: Subreddit Configuration
---
# Activities `window`
# Table Of Contents
* [Overview](#overview)
@@ -24,13 +30,13 @@
# Overview
An **Activity Window** (`window`) is a group of properties that describe a **range** of [**Activities**](/docs/README.md#activity) to retrieve from Reddit and how to **filter** them.
An **Activity Window** (`window`) is a group of properties that describe a **range** of [**Activities**](../README.md#activity) to retrieve from Reddit and how to **filter** them.
The main components of an Activity Window:
* **Range** -- How many Activities ([`count`](#count)) or what time period ([`duration`](#duration)) of Activities to fetch
* **Type of Activities** -- When **fetching** from an Author's history, should it return overview (any Activities), just Submissions, or just Comments?
* **Filters** -- How the retrieved Activities should be [filtered](/docs/subreddit/components/README.md#filters) before returning them to a Rule
* **Filters** -- How the retrieved Activities should be [filtered](README.md#filters) before returning them to a Rule
As an example, if you want to run a **Recent Activity Rule** to check if a user has had activity in /r/mealtimevideos you also need to define what range of activities you want to look at from that user's history.
@@ -214,7 +220,7 @@ window:
# Filters
Activity Window can also specify [Item and Subreddit Filters](/docs/subreddit/components/README.md#filters) to filter the Activities retrieved from Reddit before they are returned to a Rule.
Activity Window can also specify [Item and Subreddit Filters](README.md#filters) to filter the Activities retrieved from Reddit before they are returned to a Rule.
Activities can be filtered **during** (`pre`) retrieval or **after** (`post`) retrieval. **When**, during the window **lifecycle**, the Activities are filtered can change the set of Activities returned to a Rule drastically.
@@ -222,10 +228,10 @@ Activities can be filtered **during** (`pre`) retrieval or **after** (`post`) re
Regardless of when you are filtering Activities the shape of the filter is the same. Filter properties:
* `subreddits` -- A [Filter Shape](/docs/subreddit/components/README.md#filter-shapes) for filtering by the [Subreddit Criteria](/docs/subreddit/components/README.md#subreddit-filter) of each Activity
* `submissionState` -- A [Filter Shape](/docs/subreddit/components/README.md#filter-shapes) for [Submission Criteria](/docs/subreddit/components/README.md#item-filter). Will run only if filtering a Submission.
* `commentState` -- A [Filter Shape](/docs/subreddit/components/README.md#filter-shapes) for [Comment Criteria](/docs/subreddit/components/README.md#item-filter). Will run only if filtering a Comment.
* `activityState` -- A [Filter Shape](/docs/subreddit/components/README.md#filter-shapes) for either [Submission or Comment Criteria](/docs/subreddit/components/README.md#item-filter). Will run only if `submissionState` or `commentState` is not defined for their respective Activity types.
* `subreddits` -- A [Filter Shape](README.md#filter-shapes) for filtering by the [Subreddit Criteria](README.md#subreddit-filter) of each Activity
* `submissionState` -- A [Filter Shape](README.md#filter-shapes) for [Submission Criteria](README.md#item-filter). Will run only if filtering a Submission.
* `commentState` -- A [Filter Shape](README.md#filter-shapes) for [Comment Criteria](README.md#item-filter). Will run only if filtering a Comment.
* `activityState` -- A [Filter Shape](README.md#filter-shapes) for either [Submission or Comment Criteria](README.md#item-filter). Will run only if `submissionState` or `commentState` is not defined for their respective Activity types.
In this example the filter only returns Activities:

View File

@@ -1,3 +1,10 @@
---
parent: Subreddit Configuration
has_toc: false
---
# Flow Control
Context Mod's behavior after a **Check** has been processed can be configured by a user. This allows a subreddit to control exactly what Runs/Checks will be processed based on the outcome (triggered or not) of a Check.
# Table of Contents
@@ -21,7 +28,7 @@ Context Mod's behavior after a **Check** has been processed can be configured by
When a Check is finished processing it can be in one of two states:
* **Triggered** -- The **Rules** defined in the Check were **triggered** which caused the **Actions** for the Check to be run
* **Failure** -- The **Rules** defined in the check were **not triggered**, based on the conditions that were set (either from the [Check condition](/docs/README.md#Checks) or [Rule Sets](/docs/subreddit/components/advancedConcepts/README.md#Rule-Sets)), and no **Actions** were run
* **Failure** -- The **Rules** defined in the check were **not triggered**, based on the conditions that were set (either from the [Check condition](../README.md#Checks) or Rule Sets, and no **Actions** were run
The behavior CM follows is based on which state it is in. The behavior can be specified **by one or both** of these **state properties** on the Check configuration:

View File

@@ -31,7 +31,7 @@
// if the nested rules pass the condition then the Rule Set triggers the Check
//
// AND = all nested rules must be triggered to make the Rule Set trigger
// AND = any of the nested Rules will be the Rule Set trigger
// OR = any of the nested Rules will be the Rule Set trigger
"condition": "AND",
// in this check we use an Attribution >10% on ONLY submissions, which is a lower requirement then the above attribution rule
// and combine it with a History rule looking for low comment engagement

View File

@@ -22,7 +22,7 @@ runs:
# if the nested rules pass the condition then the Rule Set triggers the Check
#
# AND = all nested rules must be triggered to make the Rule Set trigger
# AND = any of the nested Rules will be the Rule Set trigger
# OR = any of the nested Rules will be the Rule Set trigger
- condition: AND
# in this check we use an Attribution >10% on ONLY submissions, which is a lower requirement then the above attribution rule
# and combine it with a History rule looking for low comment engagement

View File

@@ -0,0 +1,205 @@
---
parent: Subreddit Configuration
---
# Cookbook
Here you will find useful configs for CM that provide real-world functionality. This is where you should look first for **"how do i..."** questions.
## How To Use
Each recipe includes what type of config piece it is (Rule, Check, Action, Run, etc...). Keep this in mind before copy-pasting to make sure it goes in the right place in your config.
### Copy-Pasting
If the type is **Check** or **Run** the recipe contents will have instructions in the comments on how to use it as a **full subreddit config** OR **by itself (default).** If not Check/Run then when copy-pasting you will need to ensure it is placed in the correct spot in your config.
### As Config Fragment
**Checks, Runs, Actions, and Rule** recipes can be referenced in your config without copy-pasting by using them as [Config Fragments.](../README.md#partial-configurations) These need to be placed in the correct spot in your config, just like copy-pasting, but only require the URL of the recipe instead of all the code.
To use a recipe as a fragment **copy** the URL of the config and insert into your config like this:
```yaml
- 'url:https://URL_TO_CONFIG'
```
EXAMPLE: Using the **Config** link from the [Free Karma](#remove-submissions-from-users-who-have-used-freekarma-subs-to-bypass-karma-checks) check below -- copy the **Config** link and insert it into a full subreddit config like this:
<details markdown="block">
<summary>Config</summary>
```yaml
polling:
- newSub
runs:
- name: MyFirstRun
checks:
# freekarma check
- 'url:https://github.com/FoxxMD/context-mod/blob/master/docs/subreddit/components/cookbook/freekarma.yaml'
- name: MyRegularCheck
kind: submission
# ...
```
</details>
# Recipes
## Spam Prevention
### Remove submissions from users who have used 'freekarma' subs to bypass karma checks
* Type: **Check**
* [Config](freekarma.yaml)
If the user has any activity (comment/submission) in known freekarma subreddits in the past (100 activities) then remove the submission.
### Remove submissions that are consecutively spammed by the author
* Type: **Check**
* [Config](crosspostSpam.yaml)
If the user has crossposted the same submission in the past (100 activities) 4 or more times in a row then remove the submission.
### Remove submissions if users is flooding new
* Type: **Check**
* [Config](floodingNewSubmissions.yaml)
If the user has made more than 4 submissions in your subreddit in the last 24 hours than new submissions are removed and user is tagged with a modnote.
### Remove submissions posted in diametrically-opposed subreddit
* Type: **Check**
* [Config](diametricSpam.yaml)
If the user makes the same submission to another subreddit(s) that are "thematically" opposed to your subreddit it is probably spam. This check removes it. Detects all types of submissions (including images).
### Remove comments that are consecutively spammed by the author
* Type: **Check**
* [Config](commentSpam.yaml)
If the user made the same comment (with some fuzzy matching) 4 or more times in a row in the past (100 activities or 6 months) then remove the comment.
### Remove comment if it is a chat invite link spam
* Type: **Check**
* [Config](chatSpam.yaml)
This rule goes a step further than automod can by being more discretionary about how it handles this type of spam.
* Remove the comment if:
* Comment being checked contains **only** a chat link (no other text) OR
* Chat links appear **anywhere** in three or more of the last 100 comments the Author has made
This way ContextMod can more easily distinguish between these use cases for a user commenting with a chat link:
* actual spammers who only spam a chat link
* users who may comment with a link but have context for it either in the current comment or in their history
* users who many comment with a link but it's a one-off event (no other links historically)
## Repost Detection
### Remove comments reposted from youtube video submissions
* Type: **Check**
* [Config](youtubeCommentRepost.yaml)
**Requires bot has an API Key for Youtube.**
Removes comment on reddit if the same comment is found on the youtube video the submission is for.
### Remove comments reposted from reddit submissions
* Type: **Check**
* [Config](commentRepost.yaml)
Checks top-level comments on submissions younger than 30 minutes:
* Finds other reddit submissions based on crosspost/duplicates/title/URL, takes top 10 submissions based # of upvotes
* If this comment matches any top comments from those other submissions with at least 85% sameness then it is considered a repost and removed
### Remove reposted reddit submission
* Type: **Check**
* [Config](submissionRepost.yaml)
Checks reddit for top posts with a **Title** that is 90% or more similar to the submission being checked and removes it, if found.
## Self Promotion
### Remove link submissions where the user's history is comprised of 10% or more of the same link
* Type: **Check**
* [Config](selfPromo.yaml)
If the link origin (youtube author, twitter author, etc. or regular domain for non-media links)
* comprises 10% or more of the users **entire** history in the past (100 activities or 6 months)
* or comprises 10% or more of the users **submission** history in the past (100 activities or 6 months) and the user has low engagement (<50% of history is comments or 40%> of comment are as OP)
then remove the submission
### Remove submissions posted in 'newtube' subreddits
* Type: **Check**
* [Config](newtube.yaml)
If the user makes the same submission to a 'newtube' or self-promotional subreddit it is removed and a modnote is added.
## Safety
### Remove comments on brigaded submissions when user has no history
* Type: **Check**
* [Config](brigadingNoHistory.yaml)
The users of comments on a brigaded submission (based on a special submission flair) have their comment history checked -- if they have no participation in your subreddit then the comment is removed.
### Remove submissions from users with a history of sex solicitation
* Type: **Check**
* [Config](sexSolicitationHistory.yaml)
If the author of a submission has submissions in their history that match common reddit "sex solicitation" tags (MFA, R4F, M4F, etc...) the submission is removed and a modnote added.
This is particularly useful for subreddits with underage audiences or mentally/emotionally vulnerable groups.
The check can be modified to removed comments by changing `kind: submission` to `kind: comment`
## Verification
### Verify users from r/TranscribersOfReddit
* Type: **Check**
* [Config](transcribersOfReddit.yaml)
[r/TranscribersOfReddit](https://www.reddit.com/r/transcribersofreddit) is a community of volunteers transcribing images and videos, across reddit, into plain text.
This Check detects their standard transcription template and also checks they have a history in r/transcribersofreddit -- then approves the comment and flairs the user with **Transcriber ✍️**
### Require submission authors have prior subreddit participation
* Type: **Check**
* [Config](requireNonOPParticipation.yaml)
Submission is removed if the author has **less than 5 non-OP comments** in your subreddit prior to making the submission.
### Require submission authors make a top-level comment with 15 minutes of posting
* Type: **Check**
* [Config](requireNonOPParticipation.yaml)
After making a submission the author must make a top-level comment with a regex-checkable pattern within X minutes. If the comment is not made the submission is removed.
# Monitoring
### Sticky a comment on popular submissions
* Type: **Run**
* [Config](popularSubmissionMonitoring.yaml)
This **Run** should come after any other Runs you have that may remove a Submission.
The Run will cause CM to check new submissions for 3 hours at a 10 minute interval. The bot will then make a comment and sticky it WHEN it detects the number of upvotes is abnormal for how long the Submission has been "alive".

View File

@@ -0,0 +1,44 @@
#polling:
# - newComm
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# Report comments from users with no history in the subreddit IF the submission is flaired as being brigaded
# optionally, remove comment
#
- name: Brigading No History
kind: comment
# only runs on comments in a submission with a link flair css class of 'brigaded'
itemIs:
- submissionState:
# can use any or all of these to detect brigaded submission
- link_flair_css: brigaded
#flairTemplate: 123-1234
#link_flair_text: Restricted
rules:
- name: noHistory
kind: recentActivity
# check last 100 activities that have not been removed
window:
count: 100
filterOn:
post:
commentState:
include:
- removed: false
thresholds:
# triggers if user has only one activity (this one) in your subreddit
- subreddits:
- MYSUBREDDIT
threshold: '<= 1'
actions:
- kind: report
enable: true
content: User has no history in subreddit
- kind: remove
enable: false
note: User has no history in subreddit

View File

@@ -1,9 +1,18 @@
polling:
- newComm
runs:
- checks:
- name: ban discord only spammer
description: ban a user who spams only a discord link many times historically
#polling:
# - newComm
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# Remove comments from users who spam discord and telegram links
# -- differs from just using automod:
# 1) removes comment if it is ONLY discord/telegram link
# 2) if not *only* link then checks user's history to see if link is spammed many times and only removes if it is
#
- name: ban chat only spammer
description: ban a user who spams only a chat link many times historically
kind: comment
condition: AND
rules:
@@ -13,9 +22,9 @@ runs:
- kind: remove
- kind: ban
content: spamming discord links
- name: remove discord spam
- name: remove chat spam
description: >-
remove comments from users who only link to discord or mention discord
remove comments from users who only link to chat or mention chat
link many times historically
kind: comment
condition: OR
@@ -24,8 +33,9 @@ runs:
kind: regex
criteria:
- name: only link
# https://regexr.com/70j9m
# single quotes are required to escape special characters
regex: '/^.*(discord\.gg\/[\w\d]+)$/i'
regex: '/^\s*((?:discord\.gg|t\.me|telegram\.me|telegr\.im)\/[\w\d]+)\s*$/i'
- condition: AND
rules:
- name: linkAnywhereSpam
@@ -33,15 +43,16 @@ runs:
criteria:
- name: contains link anywhere
# single quotes are required to escape special characters
regex: '/^.*(discord\.gg\/[\w\d]+).*$/i'
regex: '/((?:discord\.gg|t\.me|telegram\.me|telegr\.im)\/[\w\d]+)/i'
- name: linkAnywhereHistoricalSpam
kind: regex
criteria:
- name: contains links anywhere historically
# single quotes are required to escape special characters
regex: '/^.*(discord\.gg\/[\w\d]+).*$/i'
regex: '/((?:discord\.gg|t\.me|telegram\.me|telegr\.im)\/[\w\d]+)/i'
totalMatchThreshold: '>= 3'
lookAt: comments
window: 10
window: 100
actions:
- kind: remove
note: Chat spam link

View File

@@ -0,0 +1,71 @@
#polling:
# - newSub
# - newComm
#runs:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a series of RUNS
- name: approvals
checks:
- name: approveSubmissionOnComment
description: Approve an unapproved submission when OP comments with the magic words
kind: comment
itemIs:
# only check comment if submission is not approved and this comment is by OP
- submissionState:
- approved: false
op: true
rules:
- name: OPMagic
kind: regex
criteria:
# YOU NEED TO EDIT THIS REGEX TO MATCH THE PATTERN THE OP'S COMMENT SHOULD HAVE IN ORDER TO VERIFY THE SUBMISSION
- regex: '/Say Please/i'
actions:
- kind: approve
targets:
- parent
- self
# cancel any delayed dispatched actions
- kind: cancelDispatch
# tell action to look for delayed items matched parent (submission)
target: parent
# submission must have 'subVerification' identifier
identifier: subVerification
- name: verification
checks:
- name: waitForVerification
description: Delay processing this submission for 15 minutes
kind: submission
itemIs:
# only dispatch if this is the first time we are seeing this submission
- source:
- "poll:newSub"
- user
actions:
- kind: dispatch
target: self
# unique identifier which is a nice hint in the UI and also allows targeting this item while it is delayed
identifier: subVerification
delay: "15 minutes"
# when it is reprocessed go directly to the 'verification' run, skipping everything else
goto: verification
- name: removeNoVerification
description: Remove submission if it is not verified after delay
kind: submission
itemIs:
# only process this submission if it comes dispatch with 'subVerification' identifier and is NOT approved after 15 minutes
- source: "dispatch:subVerification"
approved: false
actions:
# if this submission is being processed it has been 5 minutes and was not cancelled by OF comment
- kind: remove
enable: true
- kind: comment
enable: true
lock: true
distinguish: true
content: 'Your submission has been removed because you did not follow verification instructions within 15 minutes of posting.'

View File

@@ -0,0 +1,54 @@
#polling:
# - newComm
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# Checks top-level comments on submissions younger than 30 minutes:
# * Finds other reddit submissions based on crosspost/duplicates/title/URL, takes top 10 submissions based # of upvotes
# * If this comment matches any comments from those other submissions with at least 85% sameness then it is considered repost
#
# optionally, bans user if they have more than one modnote for comment reposts
#
- name: commRepost
description: Check if comment has been reposted from youtube
kind: comment
itemIs:
- removed: false
approved: false
op: false
# top level comments only
depth: '< 1'
submissionState:
- age: '< 30 minutes'
condition: AND
rules:
- name: commRepost
kind: repost
criteria:
- searchOn:
- external
actions:
- kind: remove
spam: true
note: 'reposted comment from reddit with {{rules.commrepost.closestSameness}}% sameness'
- kind: ban
authorIs:
# if the author has more than one spamwatch usernote then just ban em
include:
- modActions:
- noteType: SPAM_WATCH
note: "/comment repost.*/i"
search: total
count: "> 1"
message: You have been banned for repeated spammy behavior including reposting reddit comments
note: reddit comment repost + spammy behavior
reason: reddit comment repost + spammy behavior
- name: commRepostModNote
kind: modnote
content: 'YT comment repost with {{rules.commrepost.closestSameness}}% sameness'
type: SPAM_WATCH

View File

@@ -1,14 +1,18 @@
polling:
- newComm
runs:
- checks:
# Stop users who spam the same comment many times
#polling:
# - newComm
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# Remove comments by users who spam the same comment many times
#
- name: low xp comment spam
description: X-posted comment >=4x
kind: comment
condition: AND
rules:
- name: xPostLow
- name: xPostLowComm
kind: repeatActivity
# number of "non-repeat" comments allowed between "repeat comments"
gapAllowance: 2
@@ -16,11 +20,13 @@ runs:
threshold: '>= 4'
# retrieve either last 50 comments or 6 months' of history, whichever is less
window:
count: 50
count: 100
duration: 6 months
actions:
- kind: report
enable: true
content: 'Remove => Posted same comment {{rules.xpostlow.largestRepeat}}x times'
enable: false
content: 'Remove => Posted same comment {{rules.xpostlowcomm.largestRepeat}}x times'
- kind: remove
enable: true
note: 'Posted same comment {{rules.xpostlowcomm.largestRepeat}}x times'

View File

@@ -1,7 +1,11 @@
polling:
- unmoderated
runs:
- checks:
#polling:
# - newSub
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# stop users who post low-effort, crossposted spam submissions
#
# Remove a SUBMISSION if the user has crossposted it at least 4 times in recent history AND
@@ -18,7 +22,7 @@ runs:
gapAllowance: 2
threshold: '>= 4'
window:
count: 50
count: 100
duration: 6 months
- name: lowOrOpComm
kind: history
@@ -34,12 +38,15 @@ runs:
comment: '> 40% OP'
actions:
- kind: report
enable: true
enable: false
content: >-
Remove=>{{rules.xpostlow.largestRepeat}} X-P =>
{{rules.loworopcomm.thresholdSummary}}
- kind: remove
enable: true
note: 'Repeated submission {{rules.xpostlow.largestRepeat}}x and low comment engagement'
- kind: comment
enable: true
content: >-

View File

@@ -0,0 +1,34 @@
#polling:
# - newSub
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
- name: diametricSpam
description: Check if author has posted the same image in opposite subs
kind: submission
rules:
- name: recent
kind: recentActivity
useSubmissionAsReference: true
# requires your subreddit to be running on a CM instance that supports image processing
imageDetection:
enable: true
threshold: 5
lookAt: submissions
window: 30
thresholds:
- threshold: ">= 1"
subreddits:
- AnotherSubreddit
actions:
- kind: remove
enable: true
content: "Posted same image in {{rules.recent.subSummary}}"
- kind: comment
distinguish: true
sticky: true
lock: true
content: 'You have posted the same image in another subreddit ({{rules.recent.subSummary}}) that does not make sense given the theme of this subreddit. We consider this spam and it has been removed.'

View File

@@ -0,0 +1,34 @@
#polling:
# - newSub
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# Add a mote note to users who are making more than 4 submissions a day
# and optionally remove new submissions by them
#
- name: Flooding New
description: Detect users make more than 4 submission in 24 hours
kind: submission
rules:
- name: Recent In Sub
kind: recentActivity
useSubmissionAsReference: false
window:
duration: 24 hours
fetch: submissions
thresholds:
- subreddits:
# change this to your subreddit
- MYSUBREDDIT
threshold: "> 4"
actions:
- kind: modnote
type: SPAM_WATCH
content: '{{rules.recentinsub.totalCount}} submissions in the last 24 hours'
- kind: remove
enable: false
note: '{{rules.recentinsub.totalCount}} submissions in the last 24 hours'

View File

@@ -0,0 +1,45 @@
#polling:
# - newSub
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# Remove submissions from users who have recent activity in freekarma subs in the last 100 activities
#
- name: freekarma removal
description: Remove submission if user has used freekarma sub recently
kind: submission
rules:
- name: freekarma
kind: recentActivity
window: 100
useSubmissionAsReference: false
thresholds:
- subreddits:
- FreeKarma4U
- FreeKarma4You
- freekarmaforyou
- KarmaFarming4Pros
- KarmaStore
- upvote
- promote
- shamelessplug
- upvote
- FreeUpVotes
- GiveMeKarma
- nsfwkarma
- GetFreeKarmaAnyTime
- freekarma2021
- FreeKarma2022
- KarmaRocket
- FREEKARMA4PORN
actions:
- kind: report
enable: false
content: 'Remove => {{rules.freekarma.totalCount}} activities in freekarma subs'
- kind: remove
enable: true
note: '{{rules.freekarma.totalCount}} activities in freekarma subs'

View File

@@ -0,0 +1,55 @@
#polling:
# - newSub
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# Add a mote note to users who make a submission that is also posted to a 'newtube' subreddit
# and optionally remove new submission
#
- name: Newtube Submission
description: Tag user if submission was posted in 'newtube' subreddit
kind: submission
rules:
- name: newTube
kind: recentActivity
window:
count: 100
fetch: submissions
thresholds:
- subreddits:
- AdvertiseYourVideos
- BrandNewTube
- FreeKarma4U
- FreeKarma4You
- KarmaStore
- GetMoreSubsYT
- GetMoreViewsYT
- NewTubers
- promote
- PromoteGamingVideos
- shamelessplug
- SelfPromotionYouTube
- SmallYTChannel
- SmallYoutubers
- upvote
- youtubestartups
- YouTube_startups
- YoutubeSelfPromotions
- YoutubeSelfPromotion
- YouTubeSubscribeBoost
- youtubepromotion
- YTPromo
- Youtubeviews
- YouTube_startups
actions:
- name: newtubeModTag
kind: modnote
type: SPAM_WATCH
content: 'New Tube => {{rules.newtube.subSummary}}{{rules.newtubeall.subSummary}}'
- kind: remove
enable: false
note: 'New Tube => {{rules.newtube.subSummary}}{{rules.newtubeall.subSummary}}'

View File

@@ -0,0 +1,89 @@
polling:
- newSub
runs:
- name: MyRegularRun
itemIs:
# regular run/checks should only run on new activities or if from dashboard
- source:
- 'poll:newSub'
- 'poll:newComm'
- 'user'
checks:
- name: RuleBreakingCheck1
kind: submission
# ...
#
# your regular checks go here
#
# assuming if a Submission makes it through all of your Checks then it is "OK"
# to be Approved or generally will be visible in the subreddit (valid for monitoring for r/All)
# -- at the end of the Run add a Dispath action
- name: Dispatch For Popular Monitoring
kind: submission
actions:
- kind: dispatch
identifier: 'popular'
# CM will wait 5 minutes before processing this submission again
delay: '5 minutes'
target: 'self'
# a separate run that only processes Submissions from dispatch:popular
- name: PopularWatch
itemIs:
- source: 'dispatch:popular'
checks:
# each check here looks at submission age and tests upvotes against what you think is probably r/All number of votes
# in descending age (oldest first)
# NOTE: You should change the 'age' and 'score' tests to fit the traffic volume for your subreddit!
- name: Two Hour Check
kind: submission
itemIs:
- age: '>= 2 hours'
score: '> 100'
actions:
- kind: comment
name: popularComment
content: 'Looks like this thread is getting a lot of attention. Greetings r/All! Please keep it civil.'
sticky: true
distinguish: true
lock: true
- name: One Hour Check
kind: submission
itemIs:
- age: '>= 1 hours'
score: '> 50'
actions:
- popularComment
- name: Thirty Minute Check
kind: submission
itemIs:
- age: '>= 30 minutes'
score: '> 25'
actions:
- popularComment
- name: Ten Minute Check
kind: submission
itemIs:
- age: '>= 10 minutes'
score: '> 10'
actions:
- popularComment
# finally, if none of the popular checks passed re-dispatch submission to be checked in another 10 minutes
- name: Delay Popular Check
kind: submission
postTrigger:
# don't need to add this Actioned Events
recordTo: false
itemIs:
# only monitor until submission is 3 hours old
- age: '<= 3 hours'
actions:
- kind: dispatch
identifier: 'popular'
delay: '10 minutes'
target: 'self'

View File

@@ -0,0 +1,51 @@
#polling:
# - newSub
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# Report submissions by users with less than 5 non-OP comments in our subreddit
# and optionally remove the submission
#
- name: RequireEngagement
description: Remove submission if author has less than X non-op comments in our subreddit
kind: submission
rules:
- name: LittleEngagement
kind: recentActivity
lookAt: comments
useSubmissionAsReference: false
# bot will check the last 100 NON-OP comments from user's history
window:
count: 100
fetch: comments
filterOn:
post:
commentState:
- op: false
thresholds:
subreddits:
- MYSUBREDDIT
# rule is "triggered" if there are LESS THAN 5 comments in our subreddit in the window specified (currently 100 non-op comments)
threshold: '< 5'
actions:
- kind: report # report the submission
enable: true
# the text of the report
content: 'User has <5 non-OP comments in last 100 comments'
- kind: remove # remove the submission
enable: false
note: 'User has <5 non-OP comments in last 100 comments'
- kind: comment # reply to submission with a comment
enable: false
# contents of the comment
content: We require users to have a minimum level of engagement (>5 comments on other people's posts) in our subreddit before making submissions. Your submission has been automatically removed.
sticky: true
distinguish: true
lock: true

View File

@@ -1,7 +1,10 @@
polling:
- unmoderated
runs:
- checks:
#polling:
# - newSub
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# Stop users who make link submissions with a self-promotional agenda (with reddit's suggested 10% rule)
# https://www.reddit.com/wiki/selfpromotion#wiki_guidelines_for_self-promotion_on_reddit
@@ -58,8 +61,11 @@ runs:
({{rules.attr.window}}{{rules.attrsub.window}}){{#rules.loworopcomm.thresholdSummary}}
=>
{{rules.loworopcomm.thresholdSummary}}{{/rules.loworopcomm.thresholdSummary}}
- kind: remove
enable: false
enable: true
note: '>10% of author's history is content from this creator'
- kind: comment
enable: true
content: >-
@@ -69,4 +75,3 @@ runs:
is against [reddit's self promotional
guidelines.](https://www.reddit.com/wiki/selfpromotion#wiki_guidelines_for_self-promotion_on_reddit)
distinguish: true
dryRun: true

View File

@@ -0,0 +1,33 @@
#polling:
# - newSub
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# Remove submission if user has any "redditor for [sex]..." submissions in their history
# and optionally bans user
#
- name: sexSpamHistory
description: Detect sex spam language in recent history and ban if found (most likely a bot)
kind: submission
rules:
- kind: regex
name: redditorFor
criteria:
# matches if text has common "looking for" acronym like F4M R4A etc...
- regex: '/[RFM]4[a-zA-Z\s0-9]/i'
totalMatchThreshold: "> 1"
window: 100
testOn:
- body
- title
actions:
- kind: remove
enable: true
note: 'Has sex solicitation submission history: {{rules.redditorfor.matchSample}}'
- kind: modnote
type: ABUSE_WARNING
content: 'Has sex solicitation submission history: {{rules.redditorfor.matchSample}}'

View File

@@ -0,0 +1,31 @@
#polling:
# - newSub
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
- name: BotRepost
description: Remove submission if it is likely a repost
kind: submission
rules:
# search reddit for similar submissions to see if it is a repost
- name: subRepost
kind: repost
criteria:
- searchOn:
# match found Submissions sameness using title against title of Submission being checked
- kind: title
# sameness (confidence) % of a title required to consider Submission being checked as a repost
matchScore: 90
actions:
# report the submission
- kind: report
enable: true
content: '{{rules.subrepost.closestSameness}} confidence this is a repost.'
# remove the submission
- kind: remove
enable: false
note: '{{rules.subrepost.closestSameness}} confidence this is a repost.'

View File

@@ -0,0 +1,41 @@
#polling:
# - newComm
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# Detect top-level comments by users from r/transcribersofreddit
# and approve/flair the user
#
- name: transcriber comment
description: approve/flair transcribed video comment
kind: comment
itemIs:
# top-level comments
depth: '< 1'
condition: AND
rules:
- name: transcribedVideoFormat
kind: regex
criteria:
- regex: '/^[\n\r\s]*\*Video Transcription\*[\n\r]+---[\S\s]+---/gim'
- name: transcribersActivity
kind: recentActivity
window:
count: 100
duration: 1 week
useSubmissionAsReference: false
thresholds:
- subreddits:
- transcribersofreddit
actions:
- kind: approve
- name: flairTranscriber
kind: flair
authorIs:
exclude:
- flairText:
- Transcriber ✍️
text: Transcriber ✍️

View File

@@ -0,0 +1,47 @@
#polling:
# - newComm
#runs:
# - checks:
#### Uncomment the code above to use this as a FULL subreddit config
####
#### Otherwise copy-paste the code below to use as a CHECK
#
# If submission type is a youtube video CM will check top comments on the video and remove comment if it at least 85% the same
# optionally, bans user if they have more than one modnote for comment reposts
#
- name: commRepostYT
description: Check if comment has been reposted from youtube
kind: comment
itemIs:
- removed: false
approved: false
op: false
condition: AND
rules:
- name: commRepost
kind: repost
criteria:
- searchOn:
- external
actions:
- kind: remove
spam: true
note: 'reposted comment from youtube with {{rules.commrepostyt.closestSameness}}% sameness'
- kind: ban
authorIs:
# if the author has more than one spamwatch usernote then just ban em
include:
- modActions:
- noteType: SPAM_WATCH
note: "/comment repost.*/i"
search: total
count: "> 1"
message: You have been banned for repeated spammy behavior including reposting youtube comments
note: yt comment repost + spammy behavior
reason: yt comment repost + spammy behavior
- name: commRepostYTModNote
kind: modnote
content: 'YT comment repost with {{rules.commrepostyt.closestSameness}}% sameness'
type: SPAM_WATCH

View File

@@ -1,8 +1,13 @@
---
title: Image Comparison
parent: Subreddit Configuration
---
# Overview
ContextMod supports comparing image content, for the purpose of detecting duplicates, with two different but complimentary systems. Image comparison behavior is available for the following rules:
* [Recent Activity](/docs/subreddit/components/recentActivity)
* [Recent Activity](in-depth/recentActivity)
* Repeat Activity (In-progress)
To enable comparisons reference the example below (at the top-level of your rule) and configure as needed:
@@ -39,6 +44,7 @@ YAML
```yaml
name: ruleWithImageDetection
kind: recentActivity
imageDetection:
enable: true
threshold: 5
fetchBehavior: extension

View File

@@ -0,0 +1,9 @@
---
parent: Subreddit Configuration
has_children: true
has_toc: true
---
# In Depth
Further details and examples for CM components.

View File

@@ -0,0 +1,36 @@
---
grand_parent: Subreddit Configuration
parent: In Depth
---
# Attribution Rule
The **Attribution** rule will aggregate an Author's content Attribution (youtube channels, twitter, website domains, etc.) and can check on their totals or percentages of all Activities over a time period:
* Total # of attributions
* As percentage of all Activity or only Submissions
* Look at all domains or only media (youtube, vimeo, etc.)
* Include self posts (by reddit domain) or not
Consult the [schema](https://json-schema.app/view/%23/%23%2Fdefinitions%2FCheckJson/%23%2Fdefinitions%2FAttributionJSONConfig?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Fcontext-mod%2Fmaster%2Fsrc%2FSchema%2FApp.json) for a complete reference of the rule's properties.
# [Template Variables](../../actionTemplating.md)
| Name | Description | Example |
|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------|
| `result` | Summary of rule results (also found in Actioned Events) | 1 Attribution(s) met the threshold of >= 20%, with 6 (40%) of 15 Total -- window: 3 years |
| `triggeredDomainCount` | Number of domains that met the threshold | 1 |
| `window` | Number or duration of Activities considered from window | 3 years |
| `largestCount` | The count from the largest aggregated domain | 6 |
| `largestPercentage` | The percentage of Activities the largest aggregated domain comprises | 40% |
| `smallestCount` | The count from the smallest aggregated domain | 1 |
| `smallestPercentage` | The percentage of Activities the smallest aggregated domain comprises | 6% |
| `countRange` | A convenience string displaying "smallestCount - largestCount" or just one number if both are the same | 5 |
| `percentRange` | A convenience string displaying "smallestPercentage - largestPercentage" or just one percentage if both are the same | 34% |
| `domainsDelim` | A comma-delimited list of all the domain URLs that met the threshold | youtube.com/example1, youtube.com/example2, rueters.com |
| `titlesDelim` | A comma-delimited list of friendly-names of the domain if one is present, otherwise the URL (IE youtube.com/c/34ldfa343 => "My Youtube Channel Title") | My Channel A, My Channel B, reuters.com |
| `threshold` | The threshold you configured for this Rule to trigger | `>= 20%` |
# Examples
* Self Promotion as percentage of all Activities [YAML](redditSelfPromoAll.yaml) | [JSON](redditSelfPromoAll.json5) - Check if Author is submitting much more than they comment.
* Self Promotion as percentage of Submissions [YAML](redditSelfPromoSubmissionsOnly.yaml) | [JSON](redditSelfPromoSubmissionsOnly.json5) - Check if any of Author's aggregated submission origins are >10% of their submissions

View File

@@ -1,3 +1,8 @@
---
grand_parent: Subreddit Configuration
parent: In Depth
---
# Author
## Rule
@@ -9,7 +14,7 @@ The **Author** rule triggers if any [AuthorCriteria](https://json-schema.app/vie
* author's subreddit flair text
* author's subreddit flair css
* author's subreddit mod status
* [Toolbox User Notes](/docs/subreddit/componentscomponents/userNotes)
* [Toolbox User Notes](../userNotes)
The Author **Rule** is best used in conjunction with other Rules to short-circuit a Check based on who the Author is. It is easier to use a Rule to do this then to write **author filters** for every Rule (and makes Rules more re-useable).
@@ -18,10 +23,10 @@ Consult the [schema](https://json-schema.app/view/%23%2Fdefinitions%2FAuthorRule
### Examples
* Basic examples
* Flair new user Submission [YAML](/docs/subreddit/componentscomponents/author/flairNewUserSubmission.yaml) | [JSON](/docs/subreddit/componentscomponents/author/flairNewUserSubmission.json5) - If the Author does not have the `vet` flair then flair the Submission with `New User`
* Flair vetted user Submission [YAML](/docs/subreddit/componentscomponents/author/flairNewUserSubmission.yaml) | [JSON](/docs/subreddit/componentscomponents/author/flairNewUserSubmission.json5) - If the Author does have the `vet` flair then flair the Submission with `Vetted`
* Flair new user Submission [YAML](flairNewUserSubmission.yaml) | [JSON](flairNewUserSubmission.json5) - If the Author does not have the `vet` flair then flair the Submission with `New User`
* Flair vetted user Submission [YAML](flairNewUserSubmission.yaml) | [JSON](flairNewUserSubmission.json5) - If the Author does have the `vet` flair then flair the Submission with `Vetted`
* Used with other Rules
* Ignore vetted user [YAML](/docs/subreddit/componentscomponents/author/flairNewUserSubmission.yaml) | [JSON](/docs/subreddit/componentscomponents/author/flairNewUserSubmission.json5) - Short-circuit the Check if the Author has the `vet` flair
* Ignore vetted user [YAML](flairNewUserSubmission.yaml) | [JSON](flairNewUserSubmission.json5) - Short-circuit the Check if the Author has the `vet` flair
## Filter
@@ -35,7 +40,7 @@ All **Rules** and **Checks** have an optional `authorIs` property that takes an
### Examples
* Skip recent activity check based on author [YAML](/docs/subreddit/componentscomponents/author/authorFilter.yaml) | [JSON](/docs/subreddit/componentscomponents/author/authorFilter.json5) - Skip a Recent Activity check for a set of subreddits if the Author of the Submission has any set of flairs.
* Skip recent activity check based on author [YAML](authorFilter.yaml) | [JSON](authorFilter.json5) - Skip a Recent Activity check for a set of subreddits if the Author of the Submission has any set of flairs.
## Flair users and submissions
@@ -45,4 +50,4 @@ Consult [User Flair schema](https://json-schema.app/view/%23%2Fdefinitions%2FUse
### Examples
* OnlyFans submissions [YAML](/docs/subreddit/componentscomponents/author/onlyfansFlair.yaml) | [JSON](/docs/subreddit/componentscomponents/author/onlyfansFlair.json5) - Check whether submitter has typical OF keywords in their profile and flair both author + submission accordingly.
* OnlyFans submissions [YAML](onlyfansFlair.yaml) | [JSON](onlyfansFlair.json5) - Check whether submitter has typical OF keywords in their profile and flair both author + submission accordingly.

View File

@@ -0,0 +1,457 @@
---
grand_parent: Subreddit Configuration
parent: In Depth
title: Filters
---
# Table of Contents
* [Filters](#filters)
* [Criteria](#criteria)
* [Filter Shapes](#filter-shapes)
* [Simple Object](#simple-object)
* [Simple List](#simple-list)
* [Filter Types](#filter-types)
* [Author Filter](#author-filter)
* [Mod Actions/Notes Filter](#mod-actionsnotes-filter)
* [Toolbox UserNotes Filter](#toolbox-usernotes-filter)
* [Item Filter](#item-filter)
* [Subreddit Filter](#subreddit-filter)
* [Named Filters](#named-filters)
* [Examples](#examples)
* [General Usage](#general-usage)
* [Usage in a Run](#usage-in-a-run)
* [Usage in a Check](#usage-in-a-check)
* [Usage in a Rule](#usage-in-a-rule)
* [Usage in an Action](#usage-in-an-action)
* [Using Author and Item Filter](#using-author-and-item-filter)
* [Filter Shapes Usage](#filter-shapes-usage)
* [Using a Simple Object](#using-a-simple-object)
* [Using a Simple List](#using-a-simple-list)
* [Using a Full Anonymous Filter](#using-a-full-anonymous-filter)
* [Using a Full Anonymous Filter with Exclude](#using-a-full-anonymous-filter-with-exclude)
* [Using a Full Named Filter](#using-a-full-named-filter)
* [Author Filter Examples](#author-filter-examples)
* [New User](#new-user)
* [New User with pattern in Name](#new-user-with-pattern-in-name)
* [User has pattern in their profile description](#user-has-pattern-in-their-profile-description)
* [Exclude moderators AND users by name](#exclude-moderators-and-users-by-name)
* [Item Filter Examples](#item-filter-examples)
* [Unmoderated comment by non-op](#unmoderated-comment-by-non-op)
* [Submission is self post with no flair](#submission-is-self-post-with-no-flair)
# Filters
**Filters** are an additional channel for determining if an Event should be processed by ContextMod. They differ from [**Rules**](../../README.md#rules) in several key ways:
* **Runs, Checks, Rules, and Actions** can **all** have Filters
* Filters test against the **current state** of the Activity (or its Author) being processed, rather than looking at history/context/etc...
* Filter test results only determine if the Run, Check, Rule, or Action **should run** -- rather than triggering it
* When the filter test **passes** the thing being tested continues to process as usual
* When the filter test **fails** the thing being tested **fails**.
A Filter has these properties:
* `include` -- An optional list of Filter Criteria. If **any** passes the filter passes.
* `exclude` -- An optional list of Filter Criteria. All **must NOT** pass for the filter to pass. Ignored if `include` is present.
* `excludeCondition` -- A [condition](../../README.md#conditions) that determines how the list of Filter Criteria are tested together
## Criteria
A **criteria** is some property of a thing (Activity or Author) can be tested, and what the expected outcome is EX:
`age: '> 2 months'` => Author is older than 2 months
**Filter Criteria** is one of more **criteria** combined together to form a set of conditions that must all be true together for the Filter Criteria to be true EX
```yaml
age: '> 2 months'
verified: true
```
The above Filter Criteria is true if:
* the Author's account is older than 2 months AND
* they have a verified email
## Filter Shapes
Generically, a "full" Filter looks like this:
```yaml
include: #optional
- name: AFilterCriteria
criteria:
#...
#...one or more Filter Criteria
exclude: #optional
#...one or more Filter Criteria
excludeCondition: OR or AND
```
But for convenience a Filter's shape can be simplified with a few assumptions:
### Simple Object
When a Filter is an object, the object is assumed to be a [Filter Criteria](#criteria) which is used in `include`
```yaml
itemIs:
approved: false
```
### Simple List
When a Filter is a list, the list is assumed to be a list of [Filter Criteria](#criteria) and used in `include`
```yaml
itemIs:
- approved: false
filtered: false
- is_self: true
```
## Filter Types
There are two types of Filter. Both types have the same "shape" in the configuration with the differences between them being:
* what they are testing on
* what criteria are available to test
### Author Filter
Test the Author of an Activity. See [Schema documentation](https://json-schema.app/view/%23%2Fdefinitions%2FAuthorCriteria?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fedge%2Fsrc%2FSchema%2FApp.json) for all possible Author Criteria
#### Mod Actions/Notes Filter
See [Mod Actions/Notes](../modActions/README.md#mod-action-filter) documentation.
#### Toolbox UserNotes Filter
See [UserNotes](../userNotes/README.md) documentation
### Item Filter
Test for properties of an Activity:
* [Comment Criteria](https://json-schema.app/view/%23%2Fdefinitions%2FCommentState?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fedge%2Fsrc%2FSchema%2FApp.json)
* [Submission Criteria](https://json-schema.app/view/%23%2Fdefinitions%2FSubmissionState?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fedge%2Fsrc%2FSchema%2FApp.json)
### Subreddit Filter
Test for properties of the Subreddit an Activity belongs to. See [Schema documentation](https://json-schema.app/view/%23%2Fdefinitions%2FSubredditCriteria?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fedge%2Fsrc%2FSchema%2FApp.json)
## Named Filters
**Named Filters** work the same as [**Named Rules**](../../README.md#named-rules) and [**Named Actions:**](../../README.md#named-actions)
**Filter Criteria** may be given a `name`. A named **Filter Criteria** can **re-used anywhere in the configuration regardless of location.** This is done by:
* specifying a name on a **Filter Criteria** **once** EX: `name: MyFilterCriteria`
* using the Filter Criteria name in place of a Filter Criteria object
```yaml
runs:
- name: MyFirstRun
checks:
- name: MyFirstCheck
kind: submission
itemIs:
- MyFilterCriteria
rules:
#...
actions:
#...
- name: MySecondCheck
kind: submission
itemIs:
include:
- name: MyFilterCriteria
criteria:
approved: false
rules:
#...
actions:
#...
```
# Examples
## General Usage
Below are examples of where filters can be used
### Usage in a Run
```yaml
runs:
# this run will only be processed if author is a contributor
- name: MyRun
authorIs:
- isContributor: true
checks:
# - ...
```
### Usage in a Check
```yaml
runs:
- name: MyRun
checks:
# check will only be processed if author is a contributor
- name: MyCheck
kind: submission
authorIs:
- isContributor: true
rules:
# ...
actions:
# ...
```
### Usage in a Rule
```yaml
runs:
- name: MyRun
checks:
- name: MyCheck
kind: submission
rules:
# rule will only run if author is a contributor
- name: MyFirstRule
kind: recentActivity
authorIs:
- isContributor: true
thresholds:
# ...
actions:
# ...
```
### Usage in an Action
```yaml
runs:
- name: MyRun
checks:
- name: MyCheck
kind: submission
rules:
- name: MyFirstRule
# ...
actions:
# action will only run if author is a contributor
- kind: approve
authorIs:
- isContributor: true
```
### Using Author and Item Filter
```yaml
runs:
- name: MyRun
checks:
# Check will only process if author is a contributor AND submission is not approved
- name: MyCheck
kind: submission
authorIs:
- isContributor: true
itemIs:
- approved: false
rules:
# ...
actions:
# ...
```
## Filter Shapes Usage
Below are examples of how filters can be structured using [filter shapes](#filter-shapes)
### Using a Simple Object
```yaml
runs:
- name: MyRun
checks:
- name: MyCheck
kind: submission
# check is only processed if submission is not approved AND not marked as nsfw
itemIs:
approved: false
over_18: false
rules:
# ...
actions:
# ...
```
### Using a Simple List
```yaml
runs:
- name: MyRun
checks:
- name: MyCheck
kind: submission
# check is only processed if submission is EITHER:
# -> not approved AND not marked as nsfw
# -> not approved AND marked as nsfw AND has flair text 'Mildly NSFW;
itemIs:
# each '-' denotes a NEW set of criteria
- approved: false
over_18: false
- link_flair_text: Mildly NSFW
over_18: true
approved: false
rules:
# ...
actions:
# ...
```
### Using a Full Anonymous Filter
```yaml
runs:
- name: MyRun
checks:
- name: MyCheck
kind: submission
# check is only processed if submission is EITHER:
# -> not approved AND not marked as nsfw
# -> not approved AND marked as nsfw AND has flair text 'Mildly NSFW;
itemIs:
include:
- approved: false
over_18: false
- link_flair_text: Mildly NSFW
over_18: true
approved: false
rules:
# ...
actions:
# ...
```
### Using a Full Anonymous Filter with Exclude
```yaml
runs:
- name: MyRun
checks:
- name: MyCheck
kind: submission
# check is only processed if submission is NOT approved
itemIs:
exclude:
- approved: true
rules:
# ...
actions:
# ...
```
### Using a Full Named Filter
```yaml
runs:
- name: MyRun
checks:
- name: MyCheck
kind: submission
# check is only processed if submission is:
# -> not approved AND not marked as nsfw
itemIs:
include:
- name: sfwNotApproved
criteria:
- approved: false
over_18: false
rules:
# ...
actions:
# ...
```
## Author Filter Examples
### New User
```yaml
# author's account is less than 30 days old AND has less than 30 comment karma
authorIs:
include:
- name: newUser
criteria:
age: < 30 days
commentKarma: < 30
```
### New User with pattern in Name
```yaml
# author's account is less than 30 days old AND has less than 30 comment karma AND has 'nsfw' in their account name
authorIs:
include:
- name: newUser
criteria:
age: < 30 days
commentKarma: < 30
name: '/nsfw/i'
```
### User has pattern in their profile description
```yaml
authorIs:
include:
- description:
- '/Add Me On Snapchat/i'
- '/Add my snapchat/i'
- '/Dm me for content/i'
- '/Will Verify/i'
```
### Exclude moderators AND users by name
Useful when CM should not run if the author is from a list of users or a moderator
```yaml
authorIs:
excludeCondition: AND
exclude:
# will not run if user is a mod or is automoderator
- isMod: true
# will not run if the user is in the list below
- name:
- User1
- User2
- User3
```
## Item Filter Examples
### Unmoderated comment by non-op
```yaml
itemIs:
- removed: false
approved: false
op: false
```
### Submission is self post with no flair
```yaml
itemIs:
- is_self: true
link_flair_text: false
```

View File

@@ -0,0 +1,73 @@
---
grand_parent: Subreddit Configuration
parent: In Depth
---
# History Rule
The **History** rule can check an Author's submission/comment statistics over a time period:
* Submission total or percentage of All Activity
* Comment total or percentage of all Activity
* Comments made as OP (commented in their own Submission) total or percentage of all Comments
* Ratio of activities against another window of activities
Consult the [schema](https://json-schema.app/view/%23%2Fdefinitions%2FHistoryJSONConfig?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Fcontext-mod%2Fmaster%2Fsrc%2FSchema%2FApp.json) for a complete reference of the rule's properties.
## Ratio
Use the `ratio` property in Criteria to test the [number of activities](../../activitiesWindow.md) found in the parent criteria against the number of activities from _another_ [activity window](../../activitiesWindow.md) defined in the ratio.
Example:
```yaml
- kind: history
criteria:
# "parent" criteria, returns all activities, in the last 100 from user's history, that occurred in r/mealtimevideos
- window:
count: 100
filterOn:
post:
subreddits:
include:
- mealtimevideos
ratio:
# "ratio" criteria, returns all activities, in the last 100 from user's history, that occurred in r/redditdev
window:
count: 100
filterOn:
post:
subreddits:
include:
- redditdev
# test (number of parent criteria activities) / (number of ratio critieria activities)
threshold: '> 1.2'
```
`threshold` may be a number or percentage `(number * 100)`
* EX `> 1.2` => There are 1.2 activities from parent criteria for every 1 ratio activities
* EX `<= 75%` => There are equal to or less than 0.75 activities from parent criteria for every 1 ratio activities
### Examples
* Low Comment Engagement [YAML](lowEngagement.yaml) | [JSON](lowEngagement.json5) - Check if Author is submitting much more than they comment.
* OP Comment Engagement [YAML](opOnlyEngagement.yaml) | [JSON](opOnlyEngagement.json5) - Check if Author is mostly engaging only in their own content
# [Template Variables](../../actionTemplating.md)
| Name | Description | Example |
|----------------------|------------------------------------------------------------------------|----------------------------------------------------|
| `result` | Summary of rule results (also found in Actioned Events) | Filtered Activities (7) were < 10 Items (2 months) |
| `activityTotal` | Total number of activities from window | 50 |
| `filteredTotal` | Total number of activities filtered from window | 7 |
| `filteredPercent` | Percentage of activities filtered from window | 14% |
| `submissionTotal` | Total number of filtered submissions from window | 4 |
| `submissionPercent` | Percentage of filtered submissions from window | 8% |
| `commentTotal` | Total number of filtered comments from window | 3 |
| `commentPercent` | Percentage of filtered comments from window | 6% |
| `opTotal` | Total number of comments as OP from filtered comments | 2 |
| `opPercent` | Percentage of comments as OP from filtered comments | 66% |
| `thresholdSummary` | A text summary of the first Criteria triggered with totals/percentages | Filtered Activities (7) were < 10 Items |
| `subredditBreakdown` | A markdown list of filtered activities by subreddit | * SubredditA - 5 (71%) \n * Subreddit B - 2 (28%) |
| `window` | Number or duration of Activities considered from window | 2 months |

View File

@@ -0,0 +1,184 @@
---
grand_parent: Subreddit Configuration
parent: In Depth
---
# ModerateHateSpeech.com Rule
# Table of Contents
* [Overview](#overview)
* [MHS Predictions](#mhs-predictions)
* [Flagged](#flagged)
* [Confidence](#confidence)
* [Usage](#usage)
* [Minimal/Default Config](#minimaldefault-config)
* [Full Config](#full-config)
* [Historical Matching](#historical-matching)
* [Examples](#examples)
# Overview
[moderatehatespeech.com](https://moderatehatespeech.com/) (MHS) is a [non-profit initiative](https://moderatehatespeech.com/about/) to identify and fight toxic and hateful content online using programmatic technology such as machine learning models.
They offer a [toxic content prediction model](https://moderatehatespeech.com/framework/) specifically trained on and for [reddit content](https://www.reddit.com/r/redditdev/comments/xdscbo/updated_bot_backed_by_moderationoriented_ml_for/) as well as partnering [directly with subreddits.](https://moderatehatespeech.com/research/subreddit-program/).
Context Mod leverages their [API](https://moderatehatespeech.com/docs/) for toxic content predictions in the **MHS Rule.**
The **MHS Rule** sends an Activity's content (title or body) to MHS which returns a prediction on whether the content is toxic and actionable by a moderator.
## MHS Predictions
MHS's toxic content predictions return two indicators about the content it analyzed. Both are available as test conditions in ContextMod.
### Flagged
MHS returns a straight "Toxic or Normal" **flag** based on how it classifies the content.
Example
* `Normal` - "I love those pineapples"
* `Toxic` - "why are we having all these people from shithole countries coming here"
### Confidence
MHS returns how **confident** it is of the flag classification on a scale of 0 to 100.
Example
"why are we having all these people from shithole countries coming here"
* Flag = `Toxic`
* Confidence = `97.12` -> The model is 97% confident the content is `Toxic`
# Usage
**An MHS Api Key is required to use this Rule**. An API Key can be acquired, for free, by creating an account at [moderatehatespeech.com](https://moderatehatespeech.com).
The Key can be provided by the bot's Operator in the [bot config credentials](https://json-schema.app/view/%23/%23%2Fdefinitions%2FBotInstanceJsonConfig/%23%2Fdefinitions%2FBotCredentialsJsonConfig?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Fcontext-mod%2Fedge%2Fsrc%2FSchema%2FOperatorConfig.json) or in the subreddit's config in the top-level `credentials` property like this:
```yaml
credentials:
mhs:
apiKey: 'myMHSApiKey'
# the rest of your config below
polling:
# ...
runs:
# ...
```
### Minimal/Default Config
ContextMod provides a reasonable default configuration for the MHS Rule if you do not wish to configure it yourself. The default configuration will trigger the rule if the MHS prediction:
* flags as `toxic`
* with `90% or greater` confidence
Example
```yaml
rules:
- kind: mhs
# rest of your rules here...
```
### Full Config
| Property | Type | Description | Default |
|--------------|---------|-------------------------------------------------------------------------------------------|---------|
| `flagged` | boolean | Test whether content is flagged as toxic (true) or normal (false) | `true` |
| `confidence` | string | Comparison against a number 0 to 100 representing how confident MHS is in the prediction | `>= 90` |
| `testOn` | array | Which parts of the Activity to send to MHS. Options: `title` and/or `body` | `body` |
Example
```yaml
rules:
- kind: mhs
criteria:
flagged: true # triggers if MHs flags the content as toxic AND
confidence: '> 66' # MHS is 66% or more confident in its prediction
testOn: # send the body of the activity to the MHS prediction service
- body
```
#### Historical Matching
Like the [Sentiment](../sentiment#historical) and [Regex](../regex#historical) rules CM can also use MHS predictions to check content from the Author's history.
Example
```yaml
rules:
- kind: mhs
# ...same config as above but can include below...
historical:
mustMatchCurrent: true # if true then CM will not check author's history unless current Activity matches MHS prediction criteria
totalMatching: '> 1' # comparison for how many activities in history must match to trigger the rule
window: 10 # specify the range of activities to check in author's history
criteria: #... if specified, overrides parent-level criteria
```
# [Template Variables](../../actionTemplating.md)
| Name | Description | Example |
|-----------------|-------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
| `result` | Summary of rule results (also found in Actioned Events) | Current Activity MHS Test: ✓ Confidence test (>= 90) PASSED MHS confidence of 99.85% Flagged pass condition of true (toxic) MATCHED MHS flag 'toxic' |
| `window` | Number or duration of Activities considered from window | 1 activities |
| `criteriaTest` | MHS value to test against | MHS confidence is > 95% |
| `totalMatching` | Total number of activities (current + historical) that matched `criteriaTest` | 1 |
# Examples
Report if MHS flags as toxic
```yaml
rules:
- kind: mhs
actions:
- kind: report
content: 'MHS flagged => {{rules.mhs.summary}}'
```
Report if MHS flags as toxic with 95% confidence
```yaml
rules:
- kind: mhs
criteria:
confidence: '>= 95'
actions:
- kind: report
content: 'MHS flagged => {{rules.mhs.summary}}'
```
Report if MHS flags as toxic and at least 3 recent activities in last 10 from author's history are also toxic
```yaml
rules:
- kind: mhs
historical:
window: 10
mustMatchCurrent: true
totalMatching: '>= 3'
actions:
- kind: report
content: 'MHS flagged => {{rules.mhs.summary}}'
```
Approve if MHS flags as NOT toxic with 95% confidence
```yaml
rules:
- kind: mhs
criteria:
confidence: '>= 95'
flagged: false
actions:
- kind: approve
```

View File

@@ -1,3 +1,10 @@
---
grand_parent: Subreddit Configuration
parent: In Depth
---
# Mod Actions
# Table of Contents
* [Overview](#overview)
@@ -9,9 +16,9 @@
# Overview
[Mod Notes](https://www.reddit.com/r/modnews/comments/t8vafc/announcing_mod_notes/) is a feature for New Reddit that allow moderators to add short, categorizable notes to Users of their subreddit, optionally associating te note with a submission/comment the User made. They are inspired by [Toolbox User Notes](https://www.reddit.com/r/toolbox/wiki/docs/usernotes) which are also [supported by ContextMod.](/docs/subreddit/components/userNotes) Reddit's **Mod Notes** also combine [Moderation Log](https://mods.reddithelp.com/hc/en-us/articles/360022402312-Moderation-Log) actions (**Mod Actions**) for the selected User alongside moderator notes, enabling a full "overview" of moderator interactions with a User in their subreddit.
[Mod Notes](https://www.reddit.com/r/modnews/comments/t8vafc/announcing_mod_notes/) is a feature for New Reddit that allow moderators to add short, categorizable notes to Users of their subreddit, optionally associating te note with a submission/comment the User made. They are inspired by [Toolbox User Notes](https://www.reddit.com/r/toolbox/wiki/docs/usernotes) which are also [supported by ContextMod.](../userNotes) Reddit's **Mod Notes** also combine [Moderation Log](https://mods.reddithelp.com/hc/en-us/articles/360022402312-Moderation-Log) actions (**Mod Actions**) for the selected User alongside moderator notes, enabling a full "overview" of moderator interactions with a User in their subreddit.
ContextMod supports adding **Mod Notes** to an Author using an [Action](/docs/subreddit/components/README.md#mod-note) and using **Mod Actions/Mod Notes** as a criteria in an [Author Filter](/docs/subreddit/components/README.md#author-filter)
ContextMod supports adding **Mod Notes** to an Author using an [Action](../../README.md#mod-note) and using **Mod Actions/Mod Notes** as a criteria in an [Author Filter](../../README.md#author-filter)
# Mod Note Action
@@ -37,7 +44,7 @@ actions:
# Mod Action Filter
ContextMod can use **Mod Actions** (from moderation log) and **Mod Notes** in an [Author Filter](/docs/subreddit/components/README.md#author-filter).
ContextMod can use **Mod Actions** (from moderation log) and **Mod Notes** in an [Author Filter](../../../README.md#author-filter).
## API Usage
@@ -61,15 +68,15 @@ Mod Action Filtering Used
In general,**do not** use Mod Actions in a Filter if:
* The filter is on a [**Comment** Check](/docs/subreddit/components/README.md#checks) and your subreddit has a high volume of Comments
* The filter is on a [Run](/docs/subreddit/components/README.md#runs) and your subreddit has a high volume of Activities
* The filter is on a [**Comment** Check](../../README.md#checks) and your subreddit has a high volume of Comments
* The filter is on a [Run](../../README.md#runs) and your subreddit has a high volume of Activities
If you need Mod Notes-like functionality for a high volume subreddit consider using [Toolbox UserNotes](/docs/subreddit/components/userNotes) instead.
If you need Mod Notes-like functionality for a high volume subreddit consider using [Toolbox UserNotes](../userNotes) instead.
In general, **do** use Mod Actions in a Filter if:
* The filter is on a [**Submission** Check](/docs/subreddit/components/README.md#checks)
* The filter is part of an [Author **Rule**](/docs/subreddit/components/README.md#author) that is processed as **late as possible in the rule order for a Check**
* The filter is on a [**Submission** Check](../../README.md#checks)
* The filter is part of an [Author **Rule**](../../README.md#author) that is processed as **late as possible in the rule order for a Check**
* Your subreddit has a low volume of Activities (less than 100 combined submissions/comments in a 10 minute period, for example)
* The filter is on an Action

View File

@@ -0,0 +1,50 @@
---
grand_parent: Subreddit Configuration
parent: In Depth
---
# Recent Activity Rule
Given a list subreddit criteria, the **Recent Activity** rule finds Activities matching those criteria in the Author's history over [window](../../activitiesWindow.md) and then allows for comparing different facets of the results.
Subreddit criteria can be:
* names
* regular expression for names
* [Subreddit meta properties](https://json-schema.app/view/%23/%23%2Fdefinitions%2FSubmissionCheckJson/%23%2Fdefinitions%2FRecentActivityRuleJSONConfig/%23%2Fdefinitions%2FActivityThreshold/%23%2Fdefinitions%2FSubredditState?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Freddit-context-bot%2Fmaster%2Fsrc%2FSchema%2FApp.json) like NSFW, description, is user profile, is author's profile, etc...
Facets available to compare from analyzed history:
* number of activities found EX `> 3` => more than 3 activities found
* aggregated karma from activities EX `> 50` => more than 50 combined karma from found activities
* number of subreddits found EX `> 5` => more than 5 distinct subreddits matching subreddit criteria found
The above can also be expressed as a percentage instead of number IE "more than 10% of activities in author history come from subreddits matching criteria"
The search can also be modified in a number of ways:
* Filter found activities using an [Item Filter](#item)
* Only return activities that match the Activity from the Event being processed
* Using image detection (pixel or perceptual hash matching)
* Only return certain types of activities (only submission or only comments)
Consult the [schema](https://json-schema.app/view/%23%2Fdefinitions%2FRecentActivityRuleJSONConfig?url=https%3A%2F%2Fraw.githubusercontent.com%2FFoxxMD%2Fcontext-mod%2Fmaster%2Fsrc%2FSchema%2FApp.json) for a complete reference of the rule's properties.
### Examples
* Free Karma Subreddits [YAML](freeKarma.yaml) | [JSON](freeKarma.json5) - Check if the Author has recently posted in any "free karma" subreddits
* Submission in Free Karma Subreddits [YAML](freeKarmaOnSubmission.yaml) | [JSON](freeKarmaOnSubmission.json5) - Check if the Author has posted the Submission this check is running on in any "free karma" subreddits recently
# [Template Variables](../../actionTemplating.md)
| Name | Description | Example |
|----------------------|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|
| `result` | Summary of rule results (also found in Actioned Events) | 9 activities found in 2 of the specified subreddits (out of 21 total) MET threshold of >= 1 activities -- subreddits: SubredditA, SubredditB |
| `window` | Number or duration of Activities considered from window | 100 activities |
| `subSummary` | Comma-delimited list of subreddits matched by the criteria | SubredditA, SubredditB |
| `subCount` | Number of subreddits that match the criteria | 2 |
| `totalCount` | Total number of activities found by criteria | 9 |
| `threshold` | The threshold used to trigger the rule | `>= 1` |
| `karmaThreshold` | If present, the karma threshold used to trigger the rule | `> 5` |
| `combinedKarma` | Total number of karma gained from the matched activities | 10 |
| `subredditBreakdown` | A markdown list of filtered activities by subreddit | * SubredditA - 5 (71%) \n * Subreddit B - 2 (28%) |

View File

@@ -0,0 +1,36 @@
---
grand_parent: Subreddit Configuration
parent: In Depth
---
# Regex Rule
The **Regex** rule matches on text content from a comment or submission in the same way automod uses regex. The rule, however, provides additional functionality automod does not:
* Can set the **number** of matches that trigger the rule (`matchThreshold`)
Which can then be used in conjunction with a [`window`](../../activitiesWindow.md) to match against activities from the history of the Author of the Activity being checked (including the Activity being checked):
* Can set the **number of Activities** that meet the `matchThreshold` to trigger the rule (`activityMatchThreshold`)
* Can set the **number of total matches** across all Activities to trigger the rule (`totalMatchThreshold`)
* Can set the **type of Activities** to check (`lookAt`)
* When an Activity is a Submission can **specify which parts of the Submission to match against** IE title, body, and/or url (`testOn`)
### Examples
* Trigger if regex matches against the current activity - [YAML](matchAnyCurrentActivity.yaml) | [JSON](matchAnyCurrentActivity.json5)
* Trigger if regex matches 5 times against the current activity - [YAML](matchThresholdCurrentActivity.yaml) | [JSON](matchThresholdCurrentActivity.json5)
* Trigger if regex matches against any part of a Submission - [YAML](matchSubmissionParts.yaml) | [JSON](matchSubmissionParts.json5)
* Trigger if regex matches any of Author's last 10 activities - [YAML](matchHistoryActivity.yaml) | [JSON](matchHistoryActivity.json5)
* Trigger if regex matches at least 3 of Author's last 10 activities - [YAML](matchActivityThresholdHistory.json5) | [JSON](matchActivityThresholdHistory.json5)
* Trigger if there are 5 regex matches in the Author's last 10 activities - [YAML](matchTotalHistoryActivity.yaml) | [JSON](matchTotalHistoryActivity.json5)
* Trigger if there are 5 regex matches in the Author's last 10 comments - [YAML](matchSubsetHistoryActivity.yaml) | [JSON](matchSubsetHistoryActivity.json5)
* Remove comments that are spamming discord links - [YAML](removeDiscordSpam.yaml) | [JSON](removeDiscordSpam.json5)
* Differs from just using automod because this config can allow one-off/organic links from users who DO NOT spam discord links but will still remove the comment if the user is spamming them
# [Template Variables](../../actionTemplating.md)
| Name | Description | Example |
|---------------|---------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
| `result` | Summary of rule results (also found in Actioned Events) | Criteria 1 ✓ -- Activity Match ✓ => 1 > 0 (Threshold > 0) and 1 Total Matches (Window: 1 Item) -- Matched Values: "example.com/test" |
| `matchSample` | A comma-delimited list of matches from activities | "example.com/test" |

Some files were not shown because too many files have changed in this diff Show More