rails-image-post-solution 0.1.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.
- checksums.yaml +7 -0
- data/.rubocop.yml +8 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +42 -0
- data/LICENSE.txt +21 -0
- data/README.md +264 -0
- data/Rakefile +8 -0
- data/app/controllers/admin/frozen_posts_controller.rb +79 -0
- data/app/controllers/admin/image_reports_controller.rb +81 -0
- data/app/controllers/admin/users_controller.rb +100 -0
- data/app/controllers/rails_image_post_solution/admin/image_reports_controller.rb +92 -0
- data/app/controllers/rails_image_post_solution/image_reports_controller.rb +87 -0
- data/app/jobs/rails_image_post_solution/image_moderation_job.rb +97 -0
- data/app/models/rails_image_post_solution/image_report.rb +57 -0
- data/app/services/rails_image_post_solution/openai_vision_service.rb +128 -0
- data/app/views/admin/frozen_posts/index.html.erb +128 -0
- data/app/views/admin/image_reports/index.html.erb +94 -0
- data/app/views/admin/image_reports/show.html.erb +138 -0
- data/app/views/admin/users/index.html.erb +93 -0
- data/app/views/admin/users/show.html.erb +198 -0
- data/app/views/rails_image_post_solution/admin/image_reports/index.html.erb +100 -0
- data/app/views/rails_image_post_solution/admin/image_reports/show.html.erb +154 -0
- data/app/views/shared/_image_report_button.html.erb +26 -0
- data/app/views/shared/_image_report_modal.html.erb +45 -0
- data/config/locales/en.yml +260 -0
- data/config/locales/ja.yml +259 -0
- data/config/routes.rb +16 -0
- data/db/migrate/20250101000001_create_rails_image_post_solution_image_reports.rb +20 -0
- data/db/migrate/20250101000002_add_ai_moderation_fields_to_image_reports.rb +12 -0
- data/lib/generators/rails_image_post_solution/install/README +27 -0
- data/lib/generators/rails_image_post_solution/install/install_generator.rb +47 -0
- data/lib/generators/rails_image_post_solution/install/templates/add_ai_moderation_fields.rb.erb +12 -0
- data/lib/generators/rails_image_post_solution/install/templates/create_image_reports.rb.erb +19 -0
- data/lib/generators/rails_image_post_solution/install/templates/rails_image_post_solution.rb +15 -0
- data/lib/rails_image_post_solution/engine.rb +22 -0
- data/lib/rails_image_post_solution/version.rb +5 -0
- data/lib/rails_image_post_solution.rb +28 -0
- metadata +150 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
ja:
|
|
2
|
+
rails_image_post_solution:
|
|
3
|
+
image_report:
|
|
4
|
+
categories:
|
|
5
|
+
r18: "R18(成人向けコンテンツ)"
|
|
6
|
+
r18g: "R18G(グロテスク)"
|
|
7
|
+
copyright: "著作権侵害"
|
|
8
|
+
spam: "スパム"
|
|
9
|
+
harassment: "嫌がらせ"
|
|
10
|
+
other: "その他"
|
|
11
|
+
statuses:
|
|
12
|
+
pending: "未確認"
|
|
13
|
+
confirmed: "不適切"
|
|
14
|
+
dismissed: "却下"
|
|
15
|
+
reviewed: "レビュー済み"
|
|
16
|
+
flash:
|
|
17
|
+
already_reported: "既にこの画像を通報しています"
|
|
18
|
+
report_received: "通報を受け付けました"
|
|
19
|
+
image_not_found: "画像が見つかりません"
|
|
20
|
+
login_required: "ログインが必要です"
|
|
21
|
+
admin:
|
|
22
|
+
report_confirmed: "通報を確認済みにしました(不適切と判定)"
|
|
23
|
+
report_dismissed: "通報を却下しました(問題なし)"
|
|
24
|
+
report_not_found: "通報が見つかりません"
|
|
25
|
+
admin_access_only: "管理者のみアクセス可能です"
|
|
26
|
+
login_required: "ログインが必要です"
|
|
27
|
+
admin:
|
|
28
|
+
index:
|
|
29
|
+
title: "画像通報管理"
|
|
30
|
+
stats:
|
|
31
|
+
total: "全通報"
|
|
32
|
+
pending: "未確認"
|
|
33
|
+
confirmed: "不適切"
|
|
34
|
+
dismissed: "却下"
|
|
35
|
+
reviewed: "レビュー済み"
|
|
36
|
+
filters:
|
|
37
|
+
all: "すべて"
|
|
38
|
+
pending: "未確認"
|
|
39
|
+
confirmed: "不適切"
|
|
40
|
+
dismissed: "却下"
|
|
41
|
+
reviewed: "レビュー済み"
|
|
42
|
+
table:
|
|
43
|
+
image: "画像"
|
|
44
|
+
reporter: "通報者"
|
|
45
|
+
reason: "通報理由"
|
|
46
|
+
status: "ステータス"
|
|
47
|
+
reported_at: "通報日時"
|
|
48
|
+
reviewer: "レビュー者"
|
|
49
|
+
actions: "アクション"
|
|
50
|
+
deleted: "削除済み"
|
|
51
|
+
system: "システム"
|
|
52
|
+
no_reason: "理由なし"
|
|
53
|
+
no_reports: "通報がありません"
|
|
54
|
+
back: "戻る"
|
|
55
|
+
detail: "詳細"
|
|
56
|
+
show:
|
|
57
|
+
title: "通報詳細"
|
|
58
|
+
reported_image: "通報された画像"
|
|
59
|
+
image_deleted: "画像が削除されています"
|
|
60
|
+
report_info: "通報情報"
|
|
61
|
+
status: "ステータス"
|
|
62
|
+
reporter: "通報者"
|
|
63
|
+
reason: "通報理由"
|
|
64
|
+
reported_at: "通報日時"
|
|
65
|
+
reviewer: "レビュー者"
|
|
66
|
+
reviewed_at: "レビュー日時"
|
|
67
|
+
system_ai: "システム(AI自動判定)"
|
|
68
|
+
no_reason: "理由なし"
|
|
69
|
+
ai_detection: "AI判定"
|
|
70
|
+
ai_detected: "AI検出"
|
|
71
|
+
confidence: "信頼度"
|
|
72
|
+
image_poster: "画像投稿者"
|
|
73
|
+
username: "ユーザー名"
|
|
74
|
+
user_status: "ステータス"
|
|
75
|
+
banned: "BAN済み"
|
|
76
|
+
suspended: "停止中"
|
|
77
|
+
active: "アクティブ"
|
|
78
|
+
all_reports_title: "この画像への全通報(%{count}件)"
|
|
79
|
+
single_report: "この画像への通報は1件のみです"
|
|
80
|
+
current: "(現在)"
|
|
81
|
+
already_reviewed: "この通報は既にレビュー済みです"
|
|
82
|
+
confirm_button: "不適切と判定"
|
|
83
|
+
dismiss_button: "却下(問題なし)"
|
|
84
|
+
confirm_action: "この画像を不適切と判定しますか?"
|
|
85
|
+
dismiss_action: "この通報を却下しますか?"
|
|
86
|
+
back_to_list: "通報一覧に戻る"
|
|
87
|
+
user_actions: "ユーザーへのアクション"
|
|
88
|
+
view_user_admin: "ユーザー管理ページへ"
|
|
89
|
+
|
|
90
|
+
# Admin namespace (outside rails_image_post_solution)
|
|
91
|
+
admin:
|
|
92
|
+
flash:
|
|
93
|
+
user_suspended: "%{name}を%{days}日間停止しました"
|
|
94
|
+
user_unsuspended: "%{name}の停止を解除しました"
|
|
95
|
+
user_banned: "%{name}をBANしました"
|
|
96
|
+
user_unbanned: "%{name}のBANを解除しました"
|
|
97
|
+
user_not_found: "ユーザーが見つかりません"
|
|
98
|
+
report_confirmed: "通報を確認済みにしました(不適切と判定)"
|
|
99
|
+
report_dismissed: "通報を却下しました(問題なし)"
|
|
100
|
+
report_not_found: "通報が見つかりません"
|
|
101
|
+
admin_access_only: "管理者のみアクセス可能です"
|
|
102
|
+
access_denied: "アクセス権限がありません"
|
|
103
|
+
stage_unfrozen: "ステージの凍結を解除しました"
|
|
104
|
+
comment_unfrozen: "コメントの凍結を解除しました"
|
|
105
|
+
stage_permanently_frozen: "ステージを永久凍結しました"
|
|
106
|
+
comment_permanently_frozen: "コメントを永久凍結しました"
|
|
107
|
+
permanent_freeze_by_admin: "管理者による永久凍結"
|
|
108
|
+
stage_deleted: "ステージを削除しました"
|
|
109
|
+
comment_deleted: "コメントを削除しました"
|
|
110
|
+
users:
|
|
111
|
+
index:
|
|
112
|
+
title: "ユーザー管理"
|
|
113
|
+
stats:
|
|
114
|
+
total: "全ユーザー"
|
|
115
|
+
active: "アクティブ"
|
|
116
|
+
suspended: "停止中"
|
|
117
|
+
banned: "BAN済み"
|
|
118
|
+
admin: "管理者"
|
|
119
|
+
filters:
|
|
120
|
+
all: "すべて"
|
|
121
|
+
active: "アクティブ"
|
|
122
|
+
suspended: "停止中"
|
|
123
|
+
banned: "BAN済み"
|
|
124
|
+
admin: "管理者"
|
|
125
|
+
table:
|
|
126
|
+
username: "ユーザー名"
|
|
127
|
+
email: "メール"
|
|
128
|
+
status: "ステータス"
|
|
129
|
+
role: "役割"
|
|
130
|
+
registered_at: "登録日"
|
|
131
|
+
post_count: "投稿数"
|
|
132
|
+
actions: "アクション"
|
|
133
|
+
status_badges:
|
|
134
|
+
banned: "BAN済み"
|
|
135
|
+
suspended: "停止中"
|
|
136
|
+
active: "アクティブ"
|
|
137
|
+
role_badges:
|
|
138
|
+
admin: "管理者"
|
|
139
|
+
user: "一般"
|
|
140
|
+
no_users: "ユーザーがいません"
|
|
141
|
+
view_reports: "通報管理"
|
|
142
|
+
back: "戻る"
|
|
143
|
+
detail: "詳細"
|
|
144
|
+
show:
|
|
145
|
+
title: "ユーザー詳細: %{name}"
|
|
146
|
+
basic_info: "基本情報"
|
|
147
|
+
username: "ユーザー名"
|
|
148
|
+
nickname: "ニックネーム"
|
|
149
|
+
email: "メール"
|
|
150
|
+
status: "ステータス"
|
|
151
|
+
ban_date: "BAN日時"
|
|
152
|
+
ban_reason: "理由"
|
|
153
|
+
suspension_expiry: "停止期限"
|
|
154
|
+
suspension_reason: "理由"
|
|
155
|
+
role: "役割"
|
|
156
|
+
registered_date: "登録日"
|
|
157
|
+
language: "言語設定"
|
|
158
|
+
activity_stats: "活動統計"
|
|
159
|
+
stage_count: "幻境投稿数"
|
|
160
|
+
comment_count: "コメント数"
|
|
161
|
+
reports_made_count: "通報した数"
|
|
162
|
+
reports_received_count: "通報された数"
|
|
163
|
+
recent_stages: "最近の幻境投稿 (最新10件)"
|
|
164
|
+
recent_comments: "最近のコメント (最新10件)"
|
|
165
|
+
report_history: "通報履歴 (受けた通報)"
|
|
166
|
+
reporter: "通報者"
|
|
167
|
+
reason: "理由"
|
|
168
|
+
report_status: "ステータス"
|
|
169
|
+
date: "日時"
|
|
170
|
+
no_posts: "投稿なし"
|
|
171
|
+
no_comments: "コメントなし"
|
|
172
|
+
no_reports: "通報なし"
|
|
173
|
+
admin_actions: "管理アクション"
|
|
174
|
+
suspend_duration: "停止期間(日数)"
|
|
175
|
+
suspend_reason: "理由"
|
|
176
|
+
suspend_reason_placeholder: "停止理由を入力"
|
|
177
|
+
suspend_button: "ユーザーを停止"
|
|
178
|
+
suspend_confirm: "このユーザーを停止しますか?"
|
|
179
|
+
ban_reason: "理由"
|
|
180
|
+
ban_reason_placeholder: "BAN理由を入力"
|
|
181
|
+
ban_button: "ユーザーをBAN"
|
|
182
|
+
ban_confirm: "このユーザーを永久BANしますか?この操作は慎重に行ってください。"
|
|
183
|
+
unsuspend_button: "停止を解除"
|
|
184
|
+
unsuspend_confirm: "このユーザーの停止を解除しますか?"
|
|
185
|
+
unban_button: "BANを解除"
|
|
186
|
+
unban_confirm: "このユーザーのBANを解除しますか?"
|
|
187
|
+
back_to_list: "ユーザー一覧に戻る"
|
|
188
|
+
view_public_profile: "公開プロフィール"
|
|
189
|
+
count_suffix: " 件"
|
|
190
|
+
frozen_posts:
|
|
191
|
+
index:
|
|
192
|
+
title: "凍結された投稿の管理"
|
|
193
|
+
stats:
|
|
194
|
+
total: "凍結済み合計"
|
|
195
|
+
temporary: "仮凍結"
|
|
196
|
+
permanent: "永久凍結"
|
|
197
|
+
filters:
|
|
198
|
+
all: "すべて"
|
|
199
|
+
temporary: "仮凍結"
|
|
200
|
+
permanent: "永久凍結"
|
|
201
|
+
table:
|
|
202
|
+
type: "タイプ"
|
|
203
|
+
content: "内容"
|
|
204
|
+
poster: "投稿者"
|
|
205
|
+
freeze_reason: "凍結理由"
|
|
206
|
+
status: "ステータス"
|
|
207
|
+
frozen_at: "凍結日時"
|
|
208
|
+
actions: "アクション"
|
|
209
|
+
post_types:
|
|
210
|
+
stage: "ステージ"
|
|
211
|
+
comment: "コメント"
|
|
212
|
+
comment_prefix: "コメント"
|
|
213
|
+
status_badges:
|
|
214
|
+
temporary: "仮凍結"
|
|
215
|
+
permanent: "永久凍結"
|
|
216
|
+
actions:
|
|
217
|
+
permanent_freeze: "永久凍結"
|
|
218
|
+
unfreeze: "解除"
|
|
219
|
+
delete: "削除"
|
|
220
|
+
confirm:
|
|
221
|
+
permanent_freeze: "本当に永久凍結しますか?"
|
|
222
|
+
unfreeze: "凍結を解除しますか?"
|
|
223
|
+
delete: "本当に削除しますか?"
|
|
224
|
+
no_frozen_posts: "凍結された投稿はありません"
|
|
225
|
+
back: "戻る"
|
|
226
|
+
image_reports:
|
|
227
|
+
flash:
|
|
228
|
+
report_confirmed: "通報を確認済みにしました(不適切と判定)"
|
|
229
|
+
report_dismissed: "通報を却下しました(問題なし)"
|
|
230
|
+
report_not_found: "通報が見つかりません"
|
|
231
|
+
|
|
232
|
+
# App namespace for shared views
|
|
233
|
+
app:
|
|
234
|
+
common:
|
|
235
|
+
cancel: "キャンセル"
|
|
236
|
+
image_report:
|
|
237
|
+
modal_title: "画像を通報"
|
|
238
|
+
select_reason: "理由を選択"
|
|
239
|
+
categories:
|
|
240
|
+
r18: "R18(成人向けコンテンツ)"
|
|
241
|
+
r18g: "R18G(グロテスク)"
|
|
242
|
+
copyright: "著作権侵害"
|
|
243
|
+
spam: "スパム"
|
|
244
|
+
harassment: "嫌がらせ"
|
|
245
|
+
other: "その他"
|
|
246
|
+
details_label: "詳細(任意)"
|
|
247
|
+
details_placeholder: "詳細を入力してください..."
|
|
248
|
+
details_help: "詳細があると、レビューに役立ちます。"
|
|
249
|
+
submit: "通報する"
|
|
250
|
+
alert_select_category: "カテゴリを選択してください"
|
|
251
|
+
alert_enter_details: "詳細を入力してください"
|
|
252
|
+
button: "通報"
|
|
253
|
+
reported_badge: "通報済み"
|
|
254
|
+
report_count:
|
|
255
|
+
other: "%{count}件の通報"
|
|
256
|
+
|
|
257
|
+
languages:
|
|
258
|
+
en: "英語"
|
|
259
|
+
ja: "日本語"
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RailsImagePostSolution::Engine.routes.draw do
|
|
4
|
+
# User-facing report API
|
|
5
|
+
resources :image_reports, only: [ :create ]
|
|
6
|
+
|
|
7
|
+
# Admin dashboard
|
|
8
|
+
namespace :admin do
|
|
9
|
+
resources :image_reports, only: %i[index show] do
|
|
10
|
+
member do
|
|
11
|
+
patch :confirm
|
|
12
|
+
patch :dismiss
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateRailsImagePostSolutionImageReports < ActiveRecord::Migration[7.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :image_reports do |t|
|
|
6
|
+
t.references :active_storage_attachment, null: false, foreign_key: true
|
|
7
|
+
t.references :user, null: true, foreign_key: true
|
|
8
|
+
t.text :reason
|
|
9
|
+
t.string :status, null: false, default: 'pending'
|
|
10
|
+
t.references :reviewed_by, foreign_key: { to_table: :users }
|
|
11
|
+
t.datetime :reviewed_at
|
|
12
|
+
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
add_index :image_reports, %i[active_storage_attachment_id user_id], unique: true,
|
|
17
|
+
name: 'index_image_reports_on_attachment_and_user'
|
|
18
|
+
add_index :image_reports, :status
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddAiModerationFieldsToImageReports < ActiveRecord::Migration[7.0]
|
|
4
|
+
def change
|
|
5
|
+
add_column :image_reports, :ai_flagged, :boolean, default: false
|
|
6
|
+
add_column :image_reports, :ai_confidence, :float
|
|
7
|
+
add_column :image_reports, :ai_categories, :text
|
|
8
|
+
add_column :image_reports, :ai_detected_at, :datetime
|
|
9
|
+
|
|
10
|
+
add_index :image_reports, :ai_flagged
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
===============================================================================
|
|
2
|
+
|
|
3
|
+
RailsImagePostSolution has been installed!
|
|
4
|
+
|
|
5
|
+
Next steps:
|
|
6
|
+
|
|
7
|
+
1. Run migrations:
|
|
8
|
+
rails db:migrate
|
|
9
|
+
|
|
10
|
+
2. Configure OpenAI API key in config/initializers/rails_image_post_solution.rb
|
|
11
|
+
or set OPENAI_API_KEY environment variable
|
|
12
|
+
|
|
13
|
+
3. Mount the engine in config/routes.rb:
|
|
14
|
+
mount RailsImagePostSolution::Engine => "/moderation"
|
|
15
|
+
|
|
16
|
+
4. Add authentication to your ApplicationController (if not already present):
|
|
17
|
+
- current_user method
|
|
18
|
+
- admin? method on User model
|
|
19
|
+
|
|
20
|
+
5. (Optional) Add freeze_post! method to your models that have images:
|
|
21
|
+
def freeze_post!(type:, reason:)
|
|
22
|
+
# Your implementation
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
For more information, see: https://github.com/your-username/rails-image-post-solution
|
|
26
|
+
|
|
27
|
+
===============================================================================
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/base"
|
|
4
|
+
require "rails/generators/migration"
|
|
5
|
+
|
|
6
|
+
module RailsImagePostSolution
|
|
7
|
+
module Generators
|
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
|
9
|
+
include Rails::Generators::Migration
|
|
10
|
+
|
|
11
|
+
source_root File.expand_path("templates", __dir__)
|
|
12
|
+
|
|
13
|
+
desc "Creates an initializer and copies migrations for RailsImagePostSolution"
|
|
14
|
+
|
|
15
|
+
def self.next_migration_number(dirname)
|
|
16
|
+
next_migration_number = current_migration_number(dirname) + 1
|
|
17
|
+
ActiveRecord::Migration.next_migration_number(next_migration_number)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def copy_initializer
|
|
21
|
+
template "rails_image_post_solution.rb", "config/initializers/rails_image_post_solution.rb"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def copy_migrations
|
|
25
|
+
migration_template "create_image_reports.rb.erb",
|
|
26
|
+
"db/migrate/create_rails_image_post_solution_image_reports.rb",
|
|
27
|
+
migration_version: migration_version
|
|
28
|
+
|
|
29
|
+
sleep 1 # Ensure different timestamps
|
|
30
|
+
|
|
31
|
+
migration_template "add_ai_moderation_fields.rb.erb",
|
|
32
|
+
"db/migrate/add_ai_moderation_fields_to_image_reports.rb",
|
|
33
|
+
migration_version: migration_version
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def show_readme
|
|
37
|
+
readme "README" if behavior == :invoke
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def migration_version
|
|
43
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/generators/rails_image_post_solution/install/templates/add_ai_moderation_fields.rb.erb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddAiModerationFieldsToImageReports < ActiveRecord::Migration<%= migration_version %>
|
|
4
|
+
def change
|
|
5
|
+
add_column :image_reports, :ai_flagged, :boolean, default: false
|
|
6
|
+
add_column :image_reports, :ai_confidence, :float
|
|
7
|
+
add_column :image_reports, :ai_categories, :text
|
|
8
|
+
add_column :image_reports, :ai_detected_at, :datetime
|
|
9
|
+
|
|
10
|
+
add_index :image_reports, :ai_flagged
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateRailsImagePostSolutionImageReports < ActiveRecord::Migration<%= migration_version %>
|
|
4
|
+
def change
|
|
5
|
+
create_table :image_reports do |t|
|
|
6
|
+
t.references :active_storage_attachment, null: false, foreign_key: true
|
|
7
|
+
t.references :user, null: true, foreign_key: true
|
|
8
|
+
t.text :reason
|
|
9
|
+
t.string :status, null: false, default: "pending"
|
|
10
|
+
t.references :reviewed_by, foreign_key: { to_table: :users }
|
|
11
|
+
t.datetime :reviewed_at
|
|
12
|
+
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
add_index :image_reports, [:active_storage_attachment_id, :user_id], unique: true, name: "index_image_reports_on_attachment_and_user"
|
|
17
|
+
add_index :image_reports, :status
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RailsImagePostSolution.configure do |config|
|
|
4
|
+
# OpenAI API key (recommended to use environment variable)
|
|
5
|
+
config.openai_api_key = ENV["OPENAI_API_KEY"]
|
|
6
|
+
|
|
7
|
+
# Auto-freeze posts when inappropriate content is detected
|
|
8
|
+
# Default: true
|
|
9
|
+
config.auto_freeze_on_flag = true
|
|
10
|
+
|
|
11
|
+
# Method name to check admin permissions
|
|
12
|
+
# Specify method name to be called on current_user
|
|
13
|
+
# Default: :admin?
|
|
14
|
+
config.admin_check_method = :admin?
|
|
15
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/engine"
|
|
4
|
+
|
|
5
|
+
module RailsImagePostSolution
|
|
6
|
+
class Engine < ::Rails::Engine
|
|
7
|
+
isolate_namespace RailsImagePostSolution
|
|
8
|
+
|
|
9
|
+
config.generators do |g|
|
|
10
|
+
g.test_framework :rspec
|
|
11
|
+
g.fixture_replacement :factory_bot
|
|
12
|
+
g.factory_bot dir: "spec/factories"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Load locales
|
|
16
|
+
config.i18n.load_path += Dir[Engine.root.join("config", "locales", "**", "*.{rb,yml}")]
|
|
17
|
+
|
|
18
|
+
initializer "rails_image_post_solution.assets" do |app|
|
|
19
|
+
app.config.assets.paths << root.join("app/assets")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "rails_image_post_solution/version"
|
|
4
|
+
require_relative "rails_image_post_solution/engine"
|
|
5
|
+
|
|
6
|
+
module RailsImagePostSolution
|
|
7
|
+
class Error < StandardError; end
|
|
8
|
+
|
|
9
|
+
# Configuration
|
|
10
|
+
class << self
|
|
11
|
+
attr_accessor :configuration
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.configure
|
|
15
|
+
self.configuration ||= Configuration.new
|
|
16
|
+
yield(configuration)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class Configuration
|
|
20
|
+
attr_accessor :openai_api_key, :auto_freeze_on_flag, :admin_check_method
|
|
21
|
+
|
|
22
|
+
def initialize
|
|
23
|
+
@openai_api_key = ENV["OPENAI_API_KEY"]
|
|
24
|
+
@auto_freeze_on_flag = true
|
|
25
|
+
@admin_check_method = :admin?
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rails-image-post-solution
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- dhq_boiler
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rails
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '8.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '8.1'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: ruby-openai
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '6.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '6.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: factory_bot_rails
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '6.0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '6.0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rspec-rails
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '6.0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '6.0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: sqlite3
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '1.4'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '1.4'
|
|
82
|
+
description: A complete solution for image reporting, AI-powered moderation using
|
|
83
|
+
OpenAI Vision API, and admin dashboard for Rails applications with Active Storage.
|
|
84
|
+
email:
|
|
85
|
+
- dhq_boiler@live.jp
|
|
86
|
+
executables: []
|
|
87
|
+
extensions: []
|
|
88
|
+
extra_rdoc_files: []
|
|
89
|
+
files:
|
|
90
|
+
- ".rubocop.yml"
|
|
91
|
+
- ".ruby-version"
|
|
92
|
+
- CHANGELOG.md
|
|
93
|
+
- LICENSE.txt
|
|
94
|
+
- README.md
|
|
95
|
+
- Rakefile
|
|
96
|
+
- app/controllers/admin/frozen_posts_controller.rb
|
|
97
|
+
- app/controllers/admin/image_reports_controller.rb
|
|
98
|
+
- app/controllers/admin/users_controller.rb
|
|
99
|
+
- app/controllers/rails_image_post_solution/admin/image_reports_controller.rb
|
|
100
|
+
- app/controllers/rails_image_post_solution/image_reports_controller.rb
|
|
101
|
+
- app/jobs/rails_image_post_solution/image_moderation_job.rb
|
|
102
|
+
- app/models/rails_image_post_solution/image_report.rb
|
|
103
|
+
- app/services/rails_image_post_solution/openai_vision_service.rb
|
|
104
|
+
- app/views/admin/frozen_posts/index.html.erb
|
|
105
|
+
- app/views/admin/image_reports/index.html.erb
|
|
106
|
+
- app/views/admin/image_reports/show.html.erb
|
|
107
|
+
- app/views/admin/users/index.html.erb
|
|
108
|
+
- app/views/admin/users/show.html.erb
|
|
109
|
+
- app/views/rails_image_post_solution/admin/image_reports/index.html.erb
|
|
110
|
+
- app/views/rails_image_post_solution/admin/image_reports/show.html.erb
|
|
111
|
+
- app/views/shared/_image_report_button.html.erb
|
|
112
|
+
- app/views/shared/_image_report_modal.html.erb
|
|
113
|
+
- config/locales/en.yml
|
|
114
|
+
- config/locales/ja.yml
|
|
115
|
+
- config/routes.rb
|
|
116
|
+
- db/migrate/20250101000001_create_rails_image_post_solution_image_reports.rb
|
|
117
|
+
- db/migrate/20250101000002_add_ai_moderation_fields_to_image_reports.rb
|
|
118
|
+
- lib/generators/rails_image_post_solution/install/README
|
|
119
|
+
- lib/generators/rails_image_post_solution/install/install_generator.rb
|
|
120
|
+
- lib/generators/rails_image_post_solution/install/templates/add_ai_moderation_fields.rb.erb
|
|
121
|
+
- lib/generators/rails_image_post_solution/install/templates/create_image_reports.rb.erb
|
|
122
|
+
- lib/generators/rails_image_post_solution/install/templates/rails_image_post_solution.rb
|
|
123
|
+
- lib/rails_image_post_solution.rb
|
|
124
|
+
- lib/rails_image_post_solution/engine.rb
|
|
125
|
+
- lib/rails_image_post_solution/version.rb
|
|
126
|
+
homepage: https://github.com/dhq-boiler/rails-image-post-solution
|
|
127
|
+
licenses:
|
|
128
|
+
- MIT
|
|
129
|
+
metadata:
|
|
130
|
+
homepage_uri: https://github.com/dhq-boiler/rails-image-post-solution
|
|
131
|
+
source_code_uri: https://github.com/dhq-boiler/rails-image-post-solution
|
|
132
|
+
changelog_uri: https://github.com/dhq-boiler/rails-image-post-solution/blob/main/CHANGELOG.md
|
|
133
|
+
rdoc_options: []
|
|
134
|
+
require_paths:
|
|
135
|
+
- lib
|
|
136
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
137
|
+
requirements:
|
|
138
|
+
- - ">="
|
|
139
|
+
- !ruby/object:Gem::Version
|
|
140
|
+
version: 3.4.7
|
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
requirements: []
|
|
147
|
+
rubygems_version: 3.6.9
|
|
148
|
+
specification_version: 4
|
|
149
|
+
summary: Rails engine for image reporting and AI-powered moderation
|
|
150
|
+
test_files: []
|