moderate 1.0.0.beta1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +96 -1
  3. data/.simplecov +2 -10
  4. data/AGENTS.md +1 -1
  5. data/Appraisals +10 -8
  6. data/CHANGELOG.md +660 -20
  7. data/CLAUDE.md +1 -1
  8. data/README.md +149 -7
  9. data/Rakefile +2 -0
  10. data/app/controllers/concerns/moderate/moderation.rb +23 -11
  11. data/app/controllers/moderate/appeals_controller.rb +9 -5
  12. data/app/controllers/moderate/application_controller.rb +3 -3
  13. data/app/controllers/moderate/notices_controller.rb +3 -6
  14. data/app/helpers/moderate/engine_helper.rb +32 -11
  15. data/app/views/moderate/appeals/new.html.erb +6 -0
  16. data/app/views/moderate/transparency_reports/_summary_card.html.erb +2 -2
  17. data/app/views/moderate/transparency_reports/show.html.erb +5 -5
  18. data/config/locales/en.yml +200 -0
  19. data/config/locales/es.yml +177 -0
  20. data/context7.json +4 -0
  21. data/db/migrate/20261018200000_add_pending_key_to_moderate_flags.rb +139 -0
  22. data/db/migrate/20261018210000_add_retention_and_classifications_to_moderate_tables.rb +103 -0
  23. data/docs/chats.md +140 -0
  24. data/docs/compliance.md +92 -3
  25. data/docs/configuration.md +30 -2
  26. data/docs/dsa-notice-form.md +1 -1
  27. data/docs/images/moderate-user-report-block-actions.webp +0 -0
  28. data/docs/madmin.md +44 -14
  29. data/docs/notifications.md +17 -4
  30. data/examples/aws_rekognition_adapter.rb +6 -6
  31. data/examples/openai_moderation_adapter.rb +1 -1
  32. data/examples/regexp_pattern_adapter.rb +68 -0
  33. data/gemfiles/{rails_7.1.gemfile → rails_8.0.gemfile} +8 -6
  34. data/gemfiles/rails_8.1.gemfile +6 -5
  35. data/lib/generators/moderate/install_generator.rb +25 -0
  36. data/lib/generators/moderate/templates/create_moderate_tables.rb.erb +17 -2
  37. data/lib/generators/moderate/templates/initializer.rb +9 -15
  38. data/lib/generators/moderate/views_generator.rb +3 -3
  39. data/lib/moderate/attachments.rb +137 -0
  40. data/lib/moderate/configuration.rb +101 -12
  41. data/lib/moderate/engine.rb +86 -25
  42. data/lib/moderate/event.rb +21 -0
  43. data/lib/moderate/filters/base.rb +1 -0
  44. data/lib/moderate/filters/wordlist.rb +5 -2
  45. data/lib/moderate/jobs/classify_job.rb +100 -16
  46. data/lib/moderate/label.rb +2 -2
  47. data/lib/moderate/macros.rb +8 -3
  48. data/lib/moderate/models/appeal.rb +10 -1
  49. data/lib/moderate/models/block.rb +23 -19
  50. data/lib/moderate/models/classification.rb +24 -0
  51. data/lib/moderate/models/concerns/actor.rb +17 -2
  52. data/lib/moderate/models/concerns/content_filterable.rb +241 -56
  53. data/lib/moderate/models/concerns/deferred_notices.rb +90 -0
  54. data/lib/moderate/models/concerns/reportable.rb +84 -4
  55. data/lib/moderate/models/flag.rb +199 -3
  56. data/lib/moderate/models/report.rb +180 -16
  57. data/lib/moderate/result.rb +3 -10
  58. data/lib/moderate/retention.rb +241 -0
  59. data/lib/moderate/services/intake_notice.rb +10 -10
  60. data/lib/moderate/services/intake_report.rb +42 -13
  61. data/lib/moderate/services/resolve_appeal.rb +8 -2
  62. data/lib/moderate/services/resolve_flag.rb +183 -35
  63. data/lib/moderate/services/resolve_report.rb +288 -35
  64. data/lib/moderate/text_validator.rb +15 -14
  65. data/lib/moderate/version.rb +1 -1
  66. data/lib/moderate.rb +337 -17
  67. data/lib/tasks/moderate.rake +23 -0
  68. metadata +24 -14
  69. data/gemfiles/rails_7.2.gemfile +0 -36
  70. data/lib/moderate/text.rb +0 -38
  71. data/lib/moderate/word_list.rb +0 -90
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 446ba3a97f77b4a88ebbd1d6e45e7935d6002be573835ef750829f54adaa47a7
4
- data.tar.gz: 799dd6c0e21cac2b0b8038e268cf02baec331717c427ddf1d51bafa482b88776
3
+ metadata.gz: 7604220d418947fa60f707ff40e41635b58f0e1dddb73b5e79d44ab4f37caf46
4
+ data.tar.gz: 48f55fa68865042efffe9c733f19ac031f89f8d1eaa1a91e03ef5f5dfaee6f48
5
5
  SHA512:
6
- metadata.gz: 00f2800700b563559a9d8d40dc2a3fea24d487d24d2f660059908a2b377cce5627354961f3bfeff0d7f1da2c5666cc9aac45c1603a48c15ff20c9ad4b2502d33
7
- data.tar.gz: c047552f0534a7df8642d2615d112723b19ecaeb62d870261c13c4fb8b114833dc0ba72ae9a646cb8e4cacba658bd1e705724c451c58a2b0348506aece0c4fbd
6
+ metadata.gz: cc7dca23c94332145107036a6fa411034f78aa17b8006341fc50ad5937ef6163cc147a02df68fd726806ca9eb5ad4b0bc922846fe1bb8c55a151a301a552d0bd
7
+ data.tar.gz: 6d0405cf47e6e8256e43bbf0b17d478ecb905451d1795a0e64dacccddf406ae2865d41e2e97ca574251be961f4b19890673bef53e94d9c40b499c8a3f0e503f2
data/.rubocop.yml CHANGED
@@ -1,8 +1,103 @@
1
+ # RuboCop for the moderate gem. CI runs `bundle exec rubocop` (the `rubocop` job in
2
+ # .github/workflows/test.yml) and expects zero offenses.
1
3
  AllCops:
2
- TargetRubyVersion: 3.2
4
+ TargetRubyVersion: 3.3
5
+ NewCops: enable
6
+ SuggestExtensions: false
7
+ Exclude:
8
+ - "gemfiles/**/*" # generated by `bundle exec appraisal generate`
9
+ - "test/dummy/db/schema.rb" # never committed; a local db task may dump one
10
+ - "test/dummy/tmp/**/*" # generator test output
11
+ - "tmp/**/*"
12
+ - "vendor/**/*"
3
13
 
4
14
  Style/StringLiterals:
5
15
  EnforcedStyle: double_quotes
6
16
 
7
17
  Style/StringLiteralsInInterpolation:
8
18
  EnforcedStyle: double_quotes
19
+
20
+ # --- The shape of this codebase ---------------------------------------------
21
+ #
22
+ # The gem explains itself in prose next to the code (the legal reasoning behind a
23
+ # decision path, the Active Record timing a callback depends on), and its decision
24
+ # services are deliberately one readable method per step of a decision. Size
25
+ # metrics count those methods, not their difficulty, so they are off; the
26
+ # complexity metrics stay on, capped at what the code is today.
27
+ Metrics/AbcSize:
28
+ Enabled: false
29
+ Metrics/BlockLength:
30
+ Enabled: false
31
+ Metrics/ClassLength:
32
+ Enabled: false
33
+ Metrics/MethodLength:
34
+ Enabled: false
35
+ Metrics/ModuleLength:
36
+ Enabled: false
37
+ Metrics/CyclomaticComplexity:
38
+ Max: 12
39
+ Metrics/PerceivedComplexity:
40
+ Max: 13
41
+ # Keyword arguments name themselves (Flag.flag! takes the nine columns it files).
42
+ Metrics/ParameterLists:
43
+ CountKeywordArgs: false
44
+
45
+ Layout/LineLength:
46
+ Max: 140
47
+ Exclude:
48
+ - "moderate.gemspec" # the description is one long, deliberate paragraph
49
+
50
+ # `has_reporting_and_blocking` / `has_reportable_content` are the ecosystem's macro
51
+ # names (has_credits, has_wallets, has_api_keys), not predicates.
52
+ Naming/PredicatePrefix:
53
+ AllowedMethods:
54
+ - has_reporting_and_blocking
55
+ - has_reportable_content
56
+
57
+ Naming/RescuedExceptionsVariableName:
58
+ PreferredName: error
59
+
60
+ # Rails' own idiom in tests: `class ActiveSupport::TestCase`, `class Moderate::XTest`.
61
+ Style/ClassAndModuleChildren:
62
+ Exclude:
63
+ - "test/**/*"
64
+
65
+ # Bang methods and `save` answer true/false by Active Record convention; the test
66
+ # recorder's `audit` / `notify` return "delivered" the way a host's hooks do.
67
+ Naming/PredicateMethod:
68
+ AllowBangMethods: true
69
+ AllowedMethods:
70
+ - call
71
+ - save
72
+ - audit
73
+ - notify
74
+
75
+ # The house style: continuation lines are indented one step, not aligned to the
76
+ # first argument or the receiver.
77
+ Layout/ArgumentAlignment:
78
+ EnforcedStyle: with_fixed_indentation
79
+ Layout/MultilineMethodCallIndentation:
80
+ EnforcedStyle: indented
81
+
82
+ # `adapter = case ref … end`: `when` and `end` line up with the assignment.
83
+ Layout/CaseIndentation:
84
+ EnforcedStyle: end
85
+ Layout/EndAlignment:
86
+ EnforcedStyleAlignWith: variable
87
+
88
+ # Configuration groups its accessors by section (filtering, hooks, the legal
89
+ # forms), each with its own comment; one grouped list would lose that.
90
+ Style/AccessorGrouping:
91
+ Enabled: false
92
+
93
+ # ActiveSupport::Concern's `class_methods do … end` opens its own scope, so a
94
+ # `private` inside it says nothing about the module's instance methods.
95
+ Lint/UselessAccessModifier:
96
+ ContextCreatingMethods:
97
+ - class_methods
98
+ - included
99
+
100
+ # Strings continued with `\` are laid out to read well where they are (aligned
101
+ # under a `raise`, or indented under a keyword); the code uses both.
102
+ Layout/LineEndStringConcatenationIndentation:
103
+ Enabled: false
data/.simplecov CHANGED
@@ -18,16 +18,8 @@ SimpleCov.start do
18
18
  # migration template IS exercised indirectly — the dummy migrates a copy of it —
19
19
  # but the .erb itself is never loaded as Ruby here.)
20
20
  # - version.rb: a single constant; nothing to cover.
21
- # - The 0.x compatibility shims (text / text_validator / word_list): legacy
22
- # profanity-validator code kept only so `validates :field, moderate: true` from
23
- # 0.x still loads (see README "Upgrading from 0.x"). They are NOT part of the
24
- # 1.0 Trust & Safety surface this suite tests, so they shouldn't pull the 1.0
25
- # coverage number down.
26
21
  add_filter "/lib/generators/"
27
22
  add_filter "/lib/moderate/version.rb"
28
- add_filter "/lib/moderate/text.rb"
29
- add_filter "/lib/moderate/text_validator.rb"
30
- add_filter "/lib/moderate/word_list.rb"
31
23
 
32
24
  # Track Ruby files in the lib directory (gem source code)
33
25
  track_files "lib/**/*.rb"
@@ -46,13 +38,13 @@ SimpleCov.start do
46
38
  minimum_coverage line: 80, branch: 60
47
39
 
48
40
  # Disambiguate parallel test runs
49
- command_name "Job #{ENV['TEST_ENV_NUMBER']}" if ENV["TEST_ENV_NUMBER"]
41
+ command_name "Job #{ENV["TEST_ENV_NUMBER"]}" if ENV["TEST_ENV_NUMBER"]
50
42
  end
51
43
 
52
44
  # Print coverage summary to terminal after tests complete
53
45
  SimpleCov.at_exit do
54
46
  SimpleCov.result.format!
55
- puts "\n" + "=" * 60
47
+ puts "\n#{"=" * 60}"
56
48
  puts "COVERAGE SUMMARY"
57
49
  puts "=" * 60
58
50
  puts "Line Coverage: #{SimpleCov.result.covered_percent.round(2)}%"
data/AGENTS.md CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  This file provides guidance to AI Agents (like OpenAI's Codex, Cursor Agent, Claude Code, etc) when working with code in this repository.
4
4
 
5
- Please read the `README.md` for a full overview of the gem's API and philosophy, and the `docs/` directory (`docs/configuration.md`, `docs/notifications.md`, `docs/compliance.md`, `docs/madmin.md`, `docs/dsa-notice-form.md`) for the detailed integration guides.
5
+ Please read the `README.md` for a full overview of the gem's API and philosophy, and the `docs/` directory (`docs/configuration.md`, `docs/notifications.md`, `docs/compliance.md`, `docs/madmin.md`, `docs/dsa-notice-form.md`, `docs/chats.md`) for the detailed integration guides.
6
6
 
7
7
  This gem is part of a coherent ecosystem (`railsfast`, `goodmail`, `telegrama`, `usage_credits`, `pricing_plans`, `wallets`, `api_keys`). Match the ecosystem conventions exactly: a single `Moderate.configure do |config| … end` block, `has_*`/verb-style class macros, adapter objects + no-op-default hook procs, string class names constantized lazily, adaptive install migrations, Minitest with a `test/dummy` app, SimpleCov, and the README/docs voice.
data/Appraisals CHANGED
@@ -1,13 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Test the minimum supported Rails version (matches the gemspec floor and the
4
- # README's "Rails 7.1+ schema" claim — the adaptive migration must work here).
5
- appraise "rails-7.1" do
6
- gem "rails", "~> 7.1.0"
7
- end
8
-
9
- appraise "rails-7.2" do
10
- gem "rails", "~> 7.2.0"
3
+ # Test the oldest supported Rails line (the gemspec floor is 8.0.5.1; this resolves to
4
+ # the newest 8.0 patch, which is what a maintained 8.0 host runs — the adaptive
5
+ # migration must work here).
6
+ appraise "rails-8.0" do
7
+ gem "rails", "~> 8.0.5", ">= 8.0.5.1"
8
+ # Rails 8.0's ActiveSupport::JSON still passes `quirks_mode:` to JSON.generate /
9
+ # JSON.parse, which json 3 rejects (ArgumentError on the first JSON column write);
10
+ # 8.1 no longer passes it. A host on 8.0 needs the same pin. Stay on the
11
+ # maintained 2.x line; 2.19.9+ carries the GHSA-x2f5-4prf-w687 fix.
12
+ gem "json", ">= 2.19.9", "< 3"
11
13
  end
12
14
 
13
15
  # Test the latest Rails version — this is the default/main Gemfile anyway.