-
Notifications
You must be signed in to change notification settings - Fork 193
/
Copy pathedition_workflow_controller.rb
303 lines (256 loc) · 9.81 KB
/
edition_workflow_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
class Admin::EditionWorkflowController < Admin::BaseController
include HistoricContentConcern
before_action :find_edition
before_action :forbid_editing_of_historic_content!
before_action :enforce_permissions!
before_action :limit_edition_access!
before_action :lock_edition
before_action :set_change_note
before_action :set_minor_change_flag
before_action :ensure_reason_given_for_force_publishing, only: :force_publish
before_action :set_previous_withdrawals, only: %i[confirm_unpublish unpublish]
rescue_from ActiveRecord::StaleObjectError do
redirect_to admin_edition_path(@edition), alert: "This document has been edited since you viewed it; you are now viewing the latest version"
end
rescue_from ActiveRecord::RecordInvalid do
redirect_to admin_edition_path(@edition),
alert: "Unable to #{action_name_as_human_interaction(params[:action])} because #{@edition.errors.full_messages.to_sentence.downcase}. Please edit it and try again."
end
rescue_from Transitions::InvalidTransition do
redirect_to admin_edition_path(@edition),
alert: "Unable to #{action_name_as_human_interaction(params[:action])} because it is not ready yet. Please try again."
end
def enforce_permissions!
case action_name
when "submit", "unschedule", "confirm_unschedule"
enforce_permission!(:update, @edition)
when "reject"
enforce_permission!(:reject, @edition)
when "publish", "schedule", "confirm_publish"
enforce_permission!(:publish, @edition)
when "force_publish", "confirm_force_publish", "force_schedule", "confirm_force_schedule"
enforce_permission!(:force_publish, @edition)
when "unpublish", "confirm_unpublish"
enforce_permission!(:unpublish, @edition)
when "unwithdraw", "confirm_unwithdraw"
enforce_permission!(:unwithdraw, @edition)
when "confirm_approve_retrospectively"
enforce_permission!(:approve, @edition)
when "approve_retrospectively"
enforce_permission!(:approve, @edition)
else
raise Whitehall::Authority::Errors::InvalidAction, action_name
end
end
def submit
@edition.submit!
redirect_to admin_edition_path(@edition),
notice: "Your document has been submitted for review by a second pair of eyes"
end
def reject
@edition.reject!
users_to_notify(@edition).each do |user|
MailNotifications.edition_rejected(user, @edition, admin_edition_url(@edition)).deliver_now
end
redirect_to new_admin_edition_editorial_remark_path(@edition),
notice: "Document rejected; please explain why in an internal note"
end
def confirm_publish
unless @edition.valid?(:publish)
redirect_to admin_edition_path(@edition), alert: @edition.errors[:base].join(". ")
end
end
def publish
edition_publisher = Whitehall.edition_services.publisher(@edition)
if edition_publisher.perform!
redirect_to admin_editions_path(session_filters || { state: :published }),
notice: "The document #{@edition.title} has been published"
else
redirect_to admin_edition_path(@edition), alert: edition_publisher.failure_reason
end
end
def confirm_force_publish
redirect_to admin_edition_path(@edition), alert: @edition.errors[:base].join(". ") and return unless @edition.valid?(:publish)
end
def force_publish
unless @edition.valid?(:publish)
return redirect_to admin_edition_path(@edition), alert: @edition.errors[:base].join(". ")
end
edition_publisher = Whitehall.edition_services.force_publisher(@edition, user: current_user, remark: force_publish_reason)
if edition_publisher.perform!
redirect_to admin_editions_path(state: :published), notice: "The document #{@edition.title} has been published"
else
redirect_to admin_edition_path(@edition), alert: edition_publisher.failure_reason
end
end
def confirm_unpublish
@unpublishing = @edition.build_unpublishing
end
def unpublish
success, message = withdrawing? ? withdraw_edition : unpublish_edition
if success
redirect_to admin_edition_path(@edition), notice: message
else
@unpublishing = @edition.unpublishing || @edition.build_unpublishing(unpublishing_params)
flash.now[:alert] = message if @unpublishing.errors.blank?
render :confirm_unpublish
end
end
def confirm_unwithdraw; end
def unwithdraw
edition_unwithdrawer = Whitehall.edition_services.unwithdrawer(@edition, user: current_user)
if edition_unwithdrawer.perform!
new_edition = @edition.document.live_edition
redirect_to admin_edition_path(new_edition), notice: "This document has been unwithdrawn"
else
flash.now[:alert] = edition_unwithdrawer.failure_reason
render :confirm_unwithdraw
end
end
def schedule
# This will enqueue a `ScheduledPublishingWorker`
edition_scheduler = Whitehall.edition_services.scheduler(@edition)
if edition_scheduler.perform!
redirect_to admin_editions_path(state: :scheduled), notice: "The document #{@edition.title} has been scheduled for publication"
else
redirect_to admin_edition_path(@edition), alert: edition_scheduler.failure_reason
end
end
def confirm_force_schedule; end
def force_schedule
force_scheduler = Whitehall.edition_services.force_scheduler(@edition)
if force_scheduler.perform!
redirect_to admin_editions_path(state: :scheduled), notice: "The document #{@edition.title} has been force scheduled for publication"
else
redirect_to admin_edition_path(@edition), alert: force_scheduler.failure_reason
end
end
def confirm_unschedule; end
def unschedule
unscheduler = Whitehall.edition_services.unscheduler(@edition)
if unscheduler.perform!
redirect_to admin_editions_path(state: :submitted), notice: "The document #{@edition.title} has been unscheduled"
else
redirect_to admin_edition_path(@edition), alert: unscheduler.failure_reason
end
end
def confirm_approve_retrospectively; end
def approve_retrospectively
if @edition.approve_retrospectively
redirect_to admin_edition_path(@edition),
notice: "Thanks for reviewing; this document is no longer marked as force-published"
else
redirect_to admin_edition_path(@edition), alert: @edition.errors.full_messages.to_sentence
end
end
private
def force_publish_reason
"Force published: #{params[:reason]}"
end
def ensure_reason_given_for_force_publishing
if params[:reason].blank?
redirect_to admin_edition_path(@edition), alert: "You cannot force publish a document without a reason"
end
end
def set_previous_withdrawals
# The limit here is entirely arbitrary with the purpose of avoiding page-load performance issues on
# documents with lots of withdrawals. This scenario is unlikely, but a limit is better than a timeout.
@previous_withdrawals = @edition.document.withdrawals.last(50)
end
def withdraw_edition
if new_withdrawal? || previous_withdrawal.present?
withdrawer = Whitehall.edition_services.withdrawer(
@edition,
user: current_user,
remark: "Withdrawn",
unpublishing: unpublishing_params,
previous_withdrawal:,
)
success = withdrawer.perform!
message = if success
"This document has been marked as withdrawn"
else
withdrawer.failure_reason
end
else
success = false
message = "Select which withdrawal date you want to use"
end
[success, message]
end
def unpublish_edition
unpublisher = Whitehall.edition_services.unpublisher(
@edition,
user: current_user,
remark: "Reset to draft",
unpublishing: unpublishing_params,
)
success = unpublisher.perform!
message = if success
"This document has been unpublished and will no longer appear on the public website"
else
unpublisher.failure_reason
end
[success, message]
end
def unpublishing_params
params.fetch(:unpublishing, {}).permit(
:unpublishing_reason_id, :alternative_url, :redirect, :explanation
)
end
def withdrawing?
unpublishing_params[:unpublishing_reason_id] == UnpublishingReason::Withdrawn.id.to_s
end
def previous_withdrawal_id
params["previous_withdrawal_id"]
end
def previous_withdrawal
return if new_withdrawal?
@previous_withdrawal ||= @edition.document.withdrawals.find_by(id: previous_withdrawal_id)
end
def new_withdrawal?
previous_withdrawal_id == "new" || @edition.document.withdrawals.none?
end
def users_to_notify(edition)
edition.authors.uniq.select(&:has_email?).reject { |a| a == current_user }
end
def find_edition
@edition = Edition.find(params[:id])
end
def lock_edition
if params[:lock_version]
@edition.lock_version = params[:lock_version]
else
render plain: "All workflow actions require a lock version", status: :unprocessable_entity
end
end
def set_change_note
if params[:edition] && params[:edition][:change_note]
@edition.change_note = params[:edition][:change_note]
end
end
def set_minor_change_flag
if params[:edition] && params[:edition][:minor_change]
@edition.minor_change = params[:edition][:minor_change]
end
end
def action_name_as_human_interaction(action_name)
case action_name.to_s
when "approve_retrospectively"
"retrospectively approve this edition"
when "confirm_unpublish"
"unpublish this edition"
when "confirm_force_publish"
"force publish this edition"
when "confirm_publish"
"publish this edition"
when "confirm_unwithdraw"
"unwithdraw this edition"
else
"#{action_name.humanize(capitalize: false)} this edition"
end
end
def session_filters
(session[:document_filters] || {}).to_h
end
end