Skip to content

Commit 6b2cfd3

Browse files
authored
Merge pull request #1866 from codidact/0valt/audits
Add audit logs for mod warning creations
2 parents 6f1474a + 67174e6 commit 6b2cfd3

File tree

6 files changed

+151
-72
lines changed

6 files changed

+151
-72
lines changed

app/controllers/mod_warning_controller.rb

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,15 @@ def create
4646
@warning = ModWarning.new(author: current_user, community_user: @user.community_user,
4747
body: params[:mod_warning][:body], is_suspension: is_suspension,
4848
suspension_end: suspension_end, active: true, read: false)
49+
4950
if @warning.save
51+
audit_warning('warning_create', @warning)
52+
5053
if is_suspension
5154
@user.community_user.update(is_suspended: is_suspension, suspension_end: suspension_end,
5255
suspension_public_comment: params[:mod_warning][:suspension_public_notice])
56+
57+
audit_warning('suspension_create', @warning)
5358
end
5459

5560
redirect_to user_path(@user)
@@ -65,8 +70,11 @@ def lift
6570
@warning.update(active: false, read: false)
6671
@user.community_user.update is_suspended: false, suspension_public_comment: nil, suspension_end: nil
6772

68-
AuditLog.moderator_audit(event_type: 'warning_lift', related: @warning, user: current_user,
69-
comment: "<<Warning #{@warning.attributes_print} >>")
73+
audit_warning('warning_lift', @warning)
74+
75+
if @warning.suspension?
76+
audit_warning('suspension_lift', @warning)
77+
end
7078

7179
flash[:success] = 'The warning or suspension has been lifted. Please consider adding an annotation ' \
7280
'explaining your reasons.'
@@ -88,4 +96,13 @@ def set_user
8896
def user_scope
8997
User.joins(:community_user).includes(:community_user, :avatar_attachment)
9098
end
99+
100+
# Adds an audit log for a given mod warning
101+
# @param event_type [String] type of the event
102+
# @param warning [ModWarning] warning to audit
103+
def audit_warning(event_type, warning)
104+
AuditLog.moderator_audit(event_type: event_type,
105+
related: warning, user: current_user,
106+
comment: "<<Warning #{warning.attributes_print} >>")
107+
end
91108
end

app/models/mod_warning.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ class ModWarning < ApplicationRecord
1010
scope :active, -> { where(active: true) }
1111
scope :to, ->(user) { where(community_user: user.community_user) }
1212

13+
# Was the warning issued with a suspension?
14+
# @return [Boolean] check result
15+
def suspension?
16+
is_suspension
17+
end
18+
19+
# Is the suspension issued with the warning still active?
20+
# @return [Boolean] check result
1321
def suspension_active?
14-
active && is_suspension && !suspension_end.past?
22+
active && suspension? && !suspension_end.past?
1523
end
1624

1725
def body_as_html
Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,33 @@
11
<table class="table is-full-width is-with-hover">
22
<thead>
3-
<tr>
4-
<th><%= t('g.type').capitalize %></th>
5-
<th><%= t('g.event').capitalize %></th>
6-
<th><%= t('g.user').capitalize %></th>
7-
<th><%= t('g.related').capitalize %></th>
8-
<th><%= t('g.comment').capitalize %></th>
9-
<th><%= t('g.created').capitalize %></th>
10-
</tr>
3+
<tr>
4+
<th><%= t('g.type').capitalize %></th>
5+
<th><%= t('g.event').capitalize %></th>
6+
<th><%= t('g.user').capitalize %></th>
7+
<th><%= t('g.related').capitalize %></th>
8+
<th><%= t('g.comment').capitalize %></th>
9+
<th><%= t('g.created').capitalize %></th>
10+
</tr>
1111
</thead>
1212
<tbody>
13-
<% @logs.each do |log| %>
14-
<tr>
15-
<td><%= log.log_type.humanize %></td>
16-
<td><%= log.event_type.humanize %></td>
17-
<td><%= user_link log.user %></td>
18-
<td>
19-
<% if log.related.present? %>
20-
<%= log.related_type %> #<%= log.related_id %>
21-
<% if log.related.respond_to? :name %>
22-
(<%= log.related.name %>)
13+
<% @logs.each do |log| %>
14+
<tr>
15+
<td class="wrap-word"><%= log.log_type.humanize %></td>
16+
<td class="wrap-word"><%= log.event_type.humanize %></td>
17+
<td><%= user_link log.user %></td>
18+
<td class="wrap-word">
19+
<% if log.related.present? %>
20+
<%= log.related_type %> #<%= log.related_id %>
21+
<% if log.related.respond_to? :name %>
22+
(<%= log.related.name %>)
23+
<% end %>
2324
<% end %>
24-
<% end %>
25-
</td>
26-
<td><pre class="pre-wrap"><%= log.comment %></pre></td>
27-
<td title="<%= log.created_at.iso8601 %>"><%= time_ago_in_words(log.created_at) %> ago</td>
28-
</tr>
29-
<% end %>
25+
</td>
26+
<td>
27+
<pre class="pre-wrap"><%= log.comment %></pre>
28+
</td>
29+
<td title="<%= log.created_at.iso8601 %>"><%= time_ago_in_words(log.created_at) %> ago</td>
30+
</tr>
31+
<% end %>
3032
</tbody>
31-
</table>
33+
</table>

app/views/mod_warning/log.html.erb

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,42 @@
11
<h1>Warnings sent to <%= user_link @user %></h1>
22

33
<table class="table is-full-width is-with-hover">
4+
<tr>
5+
<th>Date</th>
6+
<th>Type</th>
7+
<th>From</th>
8+
<th>Excerpt</th>
9+
<th>Status</th>
10+
</tr>
11+
<% @warnings.each do |w| %>
412
<tr>
5-
<th>Date</th>
6-
<th>Type</th>
7-
<th>From</th>
8-
<th>Excerpt</th>
9-
<th>Status</th>
13+
<td>
14+
<span title="<%= w.created_at.iso8601 %>"><%= time_ago_in_words(w.created_at) %> ago</span>
15+
</td>
16+
<td>
17+
<% if w.suspension? %>
18+
<% diff = ((w.suspension_end - w.created_at) / (3600 * 24)).to_i %>
19+
<span class="badge is-tag is-red is-filled nowrap">Suspension</span> (<%= diff %>d)
20+
<% else %>
21+
<span class="badge is-tag is-muted nowrap">Warning</span>
22+
<% end %>
23+
</td>
24+
<td><%= user_link w.author %></td>
25+
<td><%= raw(sanitize(render_markdown(w.body), scrubber: scrubber)) %></td>
26+
<td class="wrap-word">
27+
<% if w.suspension_active? %>
28+
<strong>Current</strong>
29+
<%= form_tag lift_mod_warning_url(@user.id), method: :post do %>
30+
<%= submit_tag '(lift)', class: 'link is-red' %>
31+
<% end %>
32+
<% elsif w.active %>
33+
<strong>Unread</strong>
34+
<% elsif w.read %>
35+
Read
36+
<% else %>
37+
<strong>Lifted</strong>
38+
<% end %>
39+
</td>
1040
</tr>
11-
<% @warnings.each do |w| %>
12-
<tr>
13-
<td>
14-
<span title="<%= w.created_at.iso8601 %>"><%= time_ago_in_words(w.created_at) %> ago</span>
15-
</td>
16-
<td>
17-
<% if w.is_suspension %>
18-
<% diff = ((w.suspension_end - w.created_at) / (3600 * 24)).to_i %>
19-
<span class="badge is-tag is-red is-filled">Suspension</span> (<%= diff %>d)
20-
<% else %>
21-
<span class="badge is-tag is-muted">Warning</span>
22-
<% end %>
23-
</td>
24-
<td>
25-
<%= user_link w.author %>
26-
</td>
27-
<td>
28-
<%= raw(sanitize(render_markdown(w.body), scrubber: scrubber)) %>
29-
</td>
30-
<td>
31-
<% if w.suspension_active? %>
32-
<strong>Current</strong>
33-
<%= form_tag lift_mod_warning_url(@user.id), method: :post do %>
34-
<%= submit_tag '(lift)', class: 'link is-red' %>
35-
<% end %>
36-
<% elsif w.active %>
37-
<strong>Unread</strong>
38-
<% elsif w.read %>
39-
Read
40-
<% else %>
41-
<strong>Lifted</strong>
42-
<% end %>
43-
</td>
44-
</tr>
45-
<% end %>
46-
</table>
41+
<% end %>
42+
</table>

test/controllers/mod_warning_controller_test.rb

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class ModWarningControllerTest < ActionController::TestCase
2121

2222
test 'mods or admins should be able to access pages' do
2323
[users(:moderator), users(:admin)].each do |user|
24-
sign_in user
24+
sign_in(user)
2525

2626
[:log, :new].each do |path|
2727
get path, params: { user_id: users(:standard_user).id }
@@ -30,6 +30,21 @@ class ModWarningControllerTest < ActionController::TestCase
3030
end
3131
end
3232

33+
test ':create should correctly create mod warnings' do
34+
user = users(:moderator)
35+
subject = users(:standard_user)
36+
37+
sign_in(user)
38+
39+
try_create_mod_warning(subject)
40+
41+
assert_redirected_to(user_path(subject))
42+
warning = assigns(:warning)
43+
assert_not_nil warning
44+
assert_audit_log('warning_create', related: warning)
45+
assert_audit_log('suspension_create', related: warning)
46+
end
47+
3348
test 'suspended user should redirect to current warning page' do
3449
sign_in users(:standard_user)
3550
mod_warnings(:first_warning).update(active: true)
@@ -75,12 +90,39 @@ class ModWarningControllerTest < ActionController::TestCase
7590

7691
std = users(:standard_user)
7792
warning = mod_warnings(:third_warning)
78-
7993
warning.update(active: true)
80-
post :lift, params: { user_id: std.id }
94+
95+
try_lift_suspension(std)
8196

8297
assert_response(:found)
8398
warning.reload
8499
assert_not warning.active
100+
101+
assert_audit_log('warning_lift', related: warning)
102+
assert_audit_log('suspension_lift', related: warning)
103+
end
104+
105+
private
106+
107+
# @param subject [User] to whom the mod warning is issued
108+
# @option opts :body [String]
109+
# @option opts :suspension_public_notice [String]
110+
# @option opts :is_suspension [Boolean]
111+
# @option opts :suspension_duration [Integer]
112+
def try_create_mod_warning(subject, **opts)
113+
post :create, params: {
114+
user_id: subject.id,
115+
mod_warning: {
116+
body: 'You have been suspended for science. Your sacrifice will not be forgotten',
117+
suspension_public_notice: 'Do not mind this suspension, nothing to see here, move along',
118+
is_suspension: true,
119+
suspension_duration: 365
120+
}.merge(opts)
121+
}
122+
end
123+
124+
# @param subject [User] for whome to lift the suspension
125+
def try_lift_suspension(subject)
126+
post :lift, params: { user_id: subject.id }
85127
end
86128
end

test/test_helper.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,20 @@ def copy_abilities(community_id)
129129
end
130130
end
131131

132+
def assert_audit_log(event_type, related: nil)
133+
log_entry = AuditLog.where(event_type: event_type)
134+
.order(created_at: :desc)
135+
.last
136+
assert_not_nil(log_entry)
137+
assert_equal event_type, log_entry['event_type']
138+
139+
if related.present?
140+
assert_equal related.id, log_entry['related_id']
141+
else
142+
assert_nil(log_entry['related_id'])
143+
end
144+
end
145+
132146
def assert_draft_deleted(user, path, *fields)
133147
base_key = "saved_post.#{user.id}.#{path}"
134148

0 commit comments

Comments
 (0)