govuk_content_models 23.0.0 → 24.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/CHANGELOG.md +10 -0
  2. data/app/models/action.rb +8 -1
  3. data/app/models/edition.rb +5 -0
  4. data/app/models/user.rb +28 -2
  5. data/app/models/workflow.rb +20 -66
  6. data/app/traits/recordable_actions.rb +53 -0
  7. data/lib/govuk_content_models.rb +4 -5
  8. data/lib/govuk_content_models/action_processors.rb +23 -0
  9. data/lib/govuk_content_models/action_processors/approve_fact_check_processor.rb +6 -0
  10. data/lib/govuk_content_models/action_processors/approve_review_processor.rb +11 -0
  11. data/lib/govuk_content_models/action_processors/archive_processor.rb +6 -0
  12. data/lib/govuk_content_models/action_processors/assign_processor.rb +12 -0
  13. data/lib/govuk_content_models/action_processors/base_processor.rb +59 -0
  14. data/lib/govuk_content_models/action_processors/cancel_scheduled_publishing_processor.rb +6 -0
  15. data/lib/govuk_content_models/action_processors/create_edition_processor.rb +22 -0
  16. data/lib/govuk_content_models/action_processors/emergency_publish_processor.rb +6 -0
  17. data/lib/govuk_content_models/action_processors/new_version_processor.rb +23 -0
  18. data/lib/govuk_content_models/action_processors/publish_processor.rb +6 -0
  19. data/lib/govuk_content_models/action_processors/receive_fact_check_processor.rb +18 -0
  20. data/lib/govuk_content_models/action_processors/request_amendments_processor.rb +15 -0
  21. data/lib/govuk_content_models/action_processors/request_review_processor.rb +6 -0
  22. data/lib/govuk_content_models/action_processors/schedule_for_publishing_processor.rb +14 -0
  23. data/lib/govuk_content_models/action_processors/send_fact_check_processor.rb +14 -0
  24. data/lib/govuk_content_models/action_processors/skip_fact_check_processor.rb +6 -0
  25. data/lib/govuk_content_models/test_helpers/action_processor_helpers.rb +39 -0
  26. data/lib/govuk_content_models/version.rb +1 -1
  27. data/test/models/action_test.rb +13 -0
  28. data/test/models/edition_test.rb +87 -64
  29. data/test/models/user_test.rb +2 -2
  30. data/test/models/workflow_test.rb +160 -55
  31. data/test/test_helper.rb +2 -0
  32. metadata +25 -7
  33. data/app/models/workflow_actor.rb +0 -157
  34. data/test/models/workflow_actor_test.rb +0 -112
@@ -0,0 +1,22 @@
1
+ module GovukContentModels
2
+ module ActionProcessors
3
+ class CreateEditionProcessor < BaseProcessor
4
+
5
+ def action_name
6
+ Action::CREATE
7
+ end
8
+
9
+ def process
10
+ format = event_attributes[:format]
11
+ format_name = "#{format}_edition" unless format.to_s.match(/edition$/)
12
+ publication_class = format_name.to_s.camelize.constantize
13
+ @edition = publication_class.create(event_attributes[:edition_attributes])
14
+ end
15
+
16
+ def record_action?
17
+ edition.persisted?
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,6 @@
1
+ module GovukContentModels
2
+ module ActionProcessors
3
+ class EmergencyPublishProcessor < BaseProcessor
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,23 @@
1
+ module GovukContentModels
2
+ module ActionProcessors
3
+ class NewVersionProcessor < BaseProcessor
4
+
5
+ def process?
6
+ edition.published?
7
+ end
8
+
9
+ def process
10
+ convert_to = event_attributes[:convert_to]
11
+ @edition = if !convert_to.nil?
12
+ edition.build_clone(convert_to.to_s.camelize.constantize)
13
+ else
14
+ edition.build_clone
15
+ end
16
+ end
17
+
18
+ def record_action?
19
+ !!edition
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,6 @@
1
+ module GovukContentModels
2
+ module ActionProcessors
3
+ class PublishProcessor < BaseProcessor
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,18 @@
1
+ module GovukContentModels
2
+ module ActionProcessors
3
+ class ReceiveFactCheckProcessor < BaseProcessor
4
+
5
+ # Always records the action.
6
+ def process
7
+ edition.perform_event_without_validations(:receive_fact_check)
8
+ # Fact checks are processed async, so the user doesn't get an opportunity
9
+ # to retry without the content that (inadvertantly) fails validation, which happens frequently.
10
+ record_action_without_validation
11
+ end
12
+
13
+ def record_action?
14
+ false
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ module GovukContentModels
2
+ module ActionProcessors
3
+ class RequestAmendmentsProcessor < BaseProcessor
4
+
5
+ def process?
6
+ if edition.in_review?
7
+ requester_different?
8
+ else
9
+ true
10
+ end
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ module GovukContentModels
2
+ module ActionProcessors
3
+ class RequestReviewProcessor < BaseProcessor
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,14 @@
1
+ module GovukContentModels
2
+ module ActionProcessors
3
+ class ScheduleForPublishingProcessor < BaseProcessor
4
+
5
+ def process
6
+ publish_at = action_attributes.delete(:publish_at).to_time.utc
7
+ action_attributes.merge!(request_details: { scheduled_time: publish_at })
8
+
9
+ edition.schedule_for_publishing(publish_at)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module GovukContentModels
2
+ module ActionProcessors
3
+ class SendFactCheckProcessor < BaseProcessor
4
+
5
+ def process
6
+ return false if action_attributes[:email_addresses].blank?
7
+ action_attributes[:comment] ||= "Fact check requested"
8
+
9
+ edition.send_fact_check
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,6 @@
1
+ module GovukContentModels
2
+ module ActionProcessors
3
+ class SkipFactCheckProcessor < BaseProcessor
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,39 @@
1
+ module GovukContentModels
2
+ module TestHelpers
3
+ module ActionProcessorHelpers
4
+ def request_review(user, edition)
5
+ user.progress(edition, { request_type: :request_review, comment: "Review this edition please." })
6
+ end
7
+
8
+ def approve_review(user, edition)
9
+ user.progress(edition, { request_type: :approve_review, comment: "I've reviewed it" })
10
+ end
11
+
12
+ def send_fact_check(user, edition, comment="Fact check this guide please.")
13
+ user.progress(edition,{ request_type: :send_fact_check, comment: comment, email_addresses: "test@test.com" })
14
+ end
15
+
16
+ def receive_fact_check(user, edition, comment="Please verify these facts.")
17
+ user.progress(edition, { request_type: :receive_fact_check, comment: comment })
18
+ end
19
+
20
+ def approve_fact_check(user, edition, comment="No changes needed, this is all correct")
21
+ user.progress(edition, { request_type: :approve_fact_check, comment: comment })
22
+ end
23
+
24
+ def request_amendments(user, edition)
25
+ user.progress(edition, { request_type: :request_amendments, comment: "More amendments are required" })
26
+ end
27
+
28
+ def publish(user, edition, comment='Yo!')
29
+ user.progress(edition, { request_type: :publish, comment: comment })
30
+ end
31
+
32
+ def schedule_for_publishing(user, edition, action_attributes)
33
+ user.progress(edition, { request_type: :schedule_for_publishing,
34
+ publish_at: action_attributes[:publish_at] || Time.zone.now.utc,
35
+ comment: action_attributes[:comment] || 'Schedule!' })
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,4 +1,4 @@
1
1
  module GovukContentModels
2
2
  # Changing this causes Jenkins to tag and release the gem into the wild
3
- VERSION = "23.0.0"
3
+ VERSION = "24.0.0"
4
4
  end
@@ -0,0 +1,13 @@
1
+ require "test_helper"
2
+
3
+ class ActionTest < ActiveSupport::TestCase
4
+ test "#to_s should return the humanized version of the request type" do
5
+ assert_equal "Approve review", Action.new(request_type: 'approve_review').to_s
6
+ end
7
+
8
+ test "#to_s should contain the scheduled time when request type is SCHEDULE_FOR_PUBLISHING" do
9
+ assert_equal "Scheduled for publishing on 12/12/2014 00:00 UTC",
10
+ Action.new(:request_type => 'schedule_for_publishing',
11
+ :request_details => { 'scheduled_time' => Date.parse('12/12/2014').to_time.utc }).to_s
12
+ end
13
+ end
@@ -68,18 +68,18 @@ class EditionTest < ActiveSupport::TestCase
68
68
  end
69
69
 
70
70
  test "it should be able to find its siblings" do
71
- @artefact2 = FactoryGirl.create(:artefact)
71
+ artefact2 = FactoryGirl.create(:artefact)
72
72
  g1 = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, version_number: 1)
73
- g2 = FactoryGirl.create(:guide_edition, panopticon_id: @artefact2.id, version_number: 1)
73
+ g2 = FactoryGirl.create(:guide_edition, panopticon_id: artefact2.id, version_number: 1)
74
74
  g3 = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, version_number: 2)
75
75
  assert_equal [], g2.siblings.to_a
76
76
  assert_equal [g3], g1.siblings.to_a
77
77
  end
78
78
 
79
79
  test "it should be able to find its previous siblings" do
80
- @artefact2 = FactoryGirl.create(:artefact)
80
+ artefact2 = FactoryGirl.create(:artefact)
81
81
  g1 = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, version_number: 1)
82
- g2 = FactoryGirl.create(:guide_edition, panopticon_id: @artefact2.id, version_number: 1)
82
+ g2 = FactoryGirl.create(:guide_edition, panopticon_id: artefact2.id, version_number: 1)
83
83
  g3 = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, version_number: 2)
84
84
 
85
85
  assert_equal [], g1.previous_siblings.to_a
@@ -108,6 +108,29 @@ class EditionTest < ActiveSupport::TestCase
108
108
  end
109
109
  end
110
110
 
111
+ context "change note" do
112
+ should "be a minor change by default" do
113
+ refute Edition.new.major_change
114
+ end
115
+ should "not be valid for major changes with a blank change note" do
116
+ edition = Edition.new(major_change: true, change_note: "")
117
+ refute edition.valid?
118
+ assert edition.errors.has_key?(:change_note)
119
+ end
120
+ should "be valid for major changes with a change note" do
121
+ edition = Edition.new(title: "Edition", version_number: 1, panopticon_id: 123, major_change: true, change_note: "Changed")
122
+ assert edition.valid?
123
+ end
124
+ should "be valid when blank for minor changes" do
125
+ edition = Edition.new(title: "Edition", version_number: 1, panopticon_id: 123, change_note: "")
126
+ assert edition.valid?
127
+ end
128
+ should "be valid when populated for minor changes" do
129
+ edition = Edition.new(title: "Edition", version_number: 1, panopticon_id: 123, change_note: "Changed")
130
+ assert edition.valid?
131
+ end
132
+ end
133
+
111
134
  test "it should build a clone" do
112
135
  edition = FactoryGirl.create(:guide_edition,
113
136
  state: "published",
@@ -634,11 +657,11 @@ class EditionTest < ActiveSupport::TestCase
634
657
  edition = FactoryGirl.create(:guide_edition_with_two_parts, panopticon_id: @artefact.id, state: "ready")
635
658
 
636
659
  user = User.create name: "bob"
637
- user.publish edition, comment: "First publication"
660
+ publish(user, edition, "First publication")
638
661
 
639
662
  second_edition = edition.build_clone
640
663
  second_edition.state = "ready"
641
- user.publish second_edition, comment: "Second publication"
664
+ publish(user, second_edition, "Second publication")
642
665
 
643
666
  # simulate link validation errors in published edition
644
667
  second_edition.parts.first.update_attribute(:body, "[register your vehicle](registering-an-imported-vehicle)")
@@ -647,7 +670,7 @@ class EditionTest < ActiveSupport::TestCase
647
670
  # fix link validation error in cloned edition by appending a '/' to the relative url
648
671
  third_edition.parts.first.body = "[register your vehicle](/registering-an-imported-vehicle)"
649
672
  third_edition.state = "ready"
650
- user.publish third_edition, comment: "Third publication"
673
+ publish(user, third_edition, "Third publication")
651
674
 
652
675
  edition.reload
653
676
  assert edition.archived?
@@ -662,7 +685,7 @@ class EditionTest < ActiveSupport::TestCase
662
685
  user = FactoryGirl.create(:user)
663
686
  edition = FactoryGirl.create(:edition, :scheduled_for_publishing)
664
687
 
665
- user.publish edition, comment: "First publication"
688
+ publish(user, edition, "First publication")
666
689
 
667
690
  assert_nil edition.reload.publish_at
668
691
  end
@@ -670,7 +693,7 @@ class EditionTest < ActiveSupport::TestCase
670
693
  test "edition can return latest status action of a specified request type" do
671
694
  edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "draft")
672
695
  user = User.create(name: "George")
673
- user.request_review edition, comment: "Requesting review"
696
+ request_review(user, edition)
674
697
 
675
698
  assert_equal edition.actions.size, 1
676
699
  assert edition.latest_status_action(Action::REQUEST_REVIEW).present?
@@ -688,17 +711,17 @@ class EditionTest < ActiveSupport::TestCase
688
711
  edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "ready")
689
712
 
690
713
  user = User.create name: "bob"
691
- user.publish edition, comment: "First publication"
714
+ publish(user, edition, "First publication")
692
715
 
693
716
  second_edition = edition.build_clone
694
717
  second_edition.update_attribute(:state, "ready")
695
718
  second_edition.save!
696
- user.publish second_edition, comment: "Second publication"
719
+ publish(user, second_edition, "Second publication")
697
720
 
698
721
  third_edition = second_edition.build_clone
699
722
  third_edition.update_attribute(:state, "ready")
700
723
  third_edition.save!
701
- user.publish third_edition, comment: "Third publication"
724
+ publish(user, third_edition, "Third publication")
702
725
 
703
726
  edition.reload
704
727
  assert edition.actions.where("request_type" => "publish")
@@ -716,12 +739,12 @@ class EditionTest < ActiveSupport::TestCase
716
739
  edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "ready")
717
740
 
718
741
  user = User.create name: "bob"
719
- user.publish edition, comment: "First publication"
742
+ publish(user, edition, "First publication")
720
743
 
721
744
  new_edition = edition.build_clone
722
745
  new_edition.state = "ready"
723
746
  new_edition.save!
724
- user.publish new_edition, comment: "Second publication"
747
+ publish(user, new_edition, "Second publication")
725
748
 
726
749
  edition = edition.reload
727
750
 
@@ -733,7 +756,7 @@ class EditionTest < ActiveSupport::TestCase
733
756
  edition.save!
734
757
 
735
758
  user = User.create name: "bob"
736
- user.publish edition, comment: "First publication"
759
+ publish(user, edition, "First publication")
737
760
 
738
761
  new_edition = edition.build_clone
739
762
  new_edition.save!
@@ -771,8 +794,8 @@ class EditionTest < ActiveSupport::TestCase
771
794
 
772
795
  edition = ProgrammeEdition.new(title: "Childcare", slug: "childcare", panopticon_id: @artefact.id)
773
796
  assert edition.can_request_review?
774
- user.request_review(edition,{comment: "Review this programme please."})
775
- assert ! user.request_amendments(edition, {comment: "Well Done, but work harder"})
797
+ request_review(user, edition)
798
+ refute request_amendments(user, edition)
776
799
  end
777
800
 
778
801
  test "a published publication with a draft edition is in progress" do
@@ -800,37 +823,37 @@ class EditionTest < ActiveSupport::TestCase
800
823
  # test denormalisation
801
824
 
802
825
  test "should denormalise an edition with an assigned user and action requesters" do
803
- @user1 = FactoryGirl.create(:user, name: "Morwenna")
804
- @user2 = FactoryGirl.create(:user, name: "John")
805
- @user3 = FactoryGirl.create(:user, name: "Nick")
826
+ user1 = FactoryGirl.create(:user, name: "Morwenna")
827
+ user2 = FactoryGirl.create(:user, name: "John")
828
+ user3 = FactoryGirl.create(:user, name: "Nick")
806
829
 
807
830
  edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "archived")
808
831
 
809
- edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "archived", assigned_to_id: @user1.id)
810
- edition.actions.create request_type: Action::CREATE, requester: @user2
811
- edition.actions.create request_type: Action::PUBLISH, requester: @user3
812
- edition.actions.create request_type: Action::ARCHIVE, requester: @user1
832
+ edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "archived", assigned_to_id: user1.id)
833
+ edition.actions.create request_type: Action::CREATE, requester: user2
834
+ edition.actions.create request_type: Action::PUBLISH, requester: user3
835
+ edition.actions.create request_type: Action::ARCHIVE, requester: user1
813
836
  edition.save! and edition.reload
814
837
 
815
- assert_equal @user1.name, edition.assignee
816
- assert_equal @user2.name, edition.creator
817
- assert_equal @user3.name, edition.publisher
818
- assert_equal @user1.name, edition.archiver
838
+ assert_equal user1.name, edition.assignee
839
+ assert_equal user2.name, edition.creator
840
+ assert_equal user3.name, edition.publisher
841
+ assert_equal user1.name, edition.archiver
819
842
  end
820
843
 
821
844
  test "should denormalise an assignee's name when an edition is assigned" do
822
- @user1 = FactoryGirl.create(:user)
823
- @user2 = FactoryGirl.create(:user)
845
+ user1 = FactoryGirl.create(:user)
846
+ user2 = FactoryGirl.create(:user)
824
847
 
825
848
  edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "draft")
826
- @user1.assign edition, @user2
849
+ user1.assign edition, user2
827
850
 
828
- assert_equal @user2, edition.assigned_to
829
- assert_equal @user2.name, edition.assignee
851
+ assert_equal user2, edition.assigned_to
852
+ assert_equal user2.name, edition.assignee
830
853
  end
831
854
 
832
855
  test "should denormalise a creator's name when an edition is created" do
833
- @user = FactoryGirl.create(:user)
856
+ user = FactoryGirl.create(:user)
834
857
  FactoryGirl.create(:live_tag, tag_id: "test-section", title: "Test section", tag_type: "section")
835
858
  artefact = FactoryGirl.create(:artefact,
836
859
  slug: "foo-bar",
@@ -842,53 +865,53 @@ class EditionTest < ActiveSupport::TestCase
842
865
  owning_app: "publisher",
843
866
  )
844
867
 
845
- edition = AnswerEdition.find_or_create_from_panopticon_data(artefact.id, @user, {})
868
+ edition = AnswerEdition.find_or_create_from_panopticon_data(artefact.id, user, {})
846
869
 
847
- assert_equal @user.name, edition.creator
870
+ assert_equal user.name, edition.creator
848
871
  end
849
872
 
850
873
  test "should denormalise a publishing user's name when an edition is published" do
851
- @user = FactoryGirl.create(:user)
874
+ user = FactoryGirl.create(:user)
852
875
 
853
876
  edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "ready")
854
- @user.publish edition, { }
877
+ publish(user, edition, "First publication")
855
878
 
856
- assert_equal @user.name, edition.publisher
879
+ assert_equal user.name, edition.publisher
857
880
  end
858
881
 
859
882
  test "should set siblings in progress to nil for new editions" do
860
- @user = FactoryGirl.create(:user)
861
- @edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "ready")
862
- @published_edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "published")
863
- assert_equal 1, @edition.version_number
864
- assert_nil @edition.sibling_in_progress
883
+ user = FactoryGirl.create(:user)
884
+ edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "ready")
885
+ published_edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "published")
886
+ assert_equal 1, edition.version_number
887
+ assert_nil edition.sibling_in_progress
865
888
  end
866
889
 
867
890
  test "should update previous editions when new edition is added" do
868
- @user = FactoryGirl.create(:user)
869
- @edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "archived")
870
- @published_edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "published")
871
- @new_edition = @published_edition.build_clone
872
- @new_edition.save!
873
- @published_edition.reload
891
+ user = FactoryGirl.create(:user)
892
+ edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "archived")
893
+ published_edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "published")
894
+ new_edition = published_edition.build_clone
895
+ new_edition.save!
896
+ published_edition.reload
874
897
 
875
- assert_equal 3, @new_edition.version_number
876
- assert_equal 3, @published_edition.sibling_in_progress
898
+ assert_equal 3, new_edition.version_number
899
+ assert_equal 3, published_edition.sibling_in_progress
877
900
  end
878
901
 
879
902
  test "should update previous editions when new edition is published" do
880
- @user = FactoryGirl.create(:user)
881
- @edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "archived")
882
- @published_edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "published")
883
- @new_edition = @published_edition.build_clone
884
- @new_edition.save!
885
- @new_edition.update_attribute(:state, "ready")
886
- @user.publish(@new_edition, comment: "Publishing this")
887
- @published_edition.reload
888
-
889
- assert_equal 3, @new_edition.version_number
890
- assert_nil @new_edition.sibling_in_progress
891
- assert_nil @published_edition.sibling_in_progress
903
+ user = FactoryGirl.create(:user)
904
+ edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "archived")
905
+ published_edition = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id, state: "published")
906
+
907
+ new_edition = published_edition.build_clone
908
+ new_edition.save!
909
+ new_edition.update_attribute(:state, "ready")
910
+ publish(user, new_edition, "First publication")
911
+
912
+ assert_equal 3, new_edition.version_number
913
+ assert_nil new_edition.sibling_in_progress
914
+ assert_nil published_edition.reload.sibling_in_progress
892
915
  end
893
916
 
894
917
  test "all subclasses should provide a working whole_body method for diffing" do