govuk_content_models 6.0.2
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.
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/.travis.yml +14 -0
- data/CONTRIBUTING.md +22 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +5 -0
- data/Rakefile +46 -0
- data/app/models/action.rb +60 -0
- data/app/models/answer_edition.rb +13 -0
- data/app/models/artefact.rb +341 -0
- data/app/models/artefact_action.rb +27 -0
- data/app/models/artefact_external_link.rb +15 -0
- data/app/models/business_support/business_size.rb +14 -0
- data/app/models/business_support/business_type.rb +14 -0
- data/app/models/business_support/location.rb +14 -0
- data/app/models/business_support/purpose.rb +14 -0
- data/app/models/business_support/sector.rb +14 -0
- data/app/models/business_support/stage.rb +14 -0
- data/app/models/business_support/support_type.rb +14 -0
- data/app/models/business_support_edition.rb +69 -0
- data/app/models/campaign_edition.rb +72 -0
- data/app/models/completed_transaction_edition.rb +14 -0
- data/app/models/curated_list.rb +32 -0
- data/app/models/edition.rb +286 -0
- data/app/models/expectant.rb +21 -0
- data/app/models/expectation.rb +12 -0
- data/app/models/guide_edition.rb +19 -0
- data/app/models/help_page_edition.rb +13 -0
- data/app/models/licence_edition.rb +35 -0
- data/app/models/local_authority.rb +58 -0
- data/app/models/local_interaction.rb +20 -0
- data/app/models/local_service.rb +49 -0
- data/app/models/local_transaction_edition.rb +49 -0
- data/app/models/overview_dashboard.rb +25 -0
- data/app/models/part.rb +28 -0
- data/app/models/parted.rb +32 -0
- data/app/models/place_edition.rb +20 -0
- data/app/models/programme_edition.rb +26 -0
- data/app/models/simple_smart_answer_edition.rb +66 -0
- data/app/models/simple_smart_answer_edition/node.rb +40 -0
- data/app/models/simple_smart_answer_edition/node/option.rb +31 -0
- data/app/models/tag.rb +88 -0
- data/app/models/transaction_edition.rb +28 -0
- data/app/models/travel_advice_edition.rb +177 -0
- data/app/models/user.rb +54 -0
- data/app/models/video_edition.rb +24 -0
- data/app/models/workflow.rb +217 -0
- data/app/models/workflow_actor.rb +141 -0
- data/app/traits/attachable.rb +60 -0
- data/app/traits/govspeak_smart_quotes_fixer.rb +19 -0
- data/app/traits/taggable.rb +113 -0
- data/app/validators/safe_html.rb +33 -0
- data/app/validators/slug_validator.rb +53 -0
- data/config/mongoid.yml +5 -0
- data/govuk_content_models.gemspec +42 -0
- data/jenkins.sh +7 -0
- data/lib/fact_check_address.rb +36 -0
- data/lib/govuk_content_models.rb +12 -0
- data/lib/govuk_content_models/require_all.rb +14 -0
- data/lib/govuk_content_models/test_helpers/factories.rb +213 -0
- data/lib/govuk_content_models/test_helpers/local_services.rb +24 -0
- data/lib/govuk_content_models/version.rb +4 -0
- data/test/fixtures/contactotron_api_response.json +1 -0
- data/test/fixtures/uploads/image.jpg +0 -0
- data/test/models/artefact_action_test.rb +123 -0
- data/test/models/artefact_external_link_test.rb +32 -0
- data/test/models/artefact_tag_test.rb +52 -0
- data/test/models/artefact_test.rb +583 -0
- data/test/models/business_support/business_size_test.rb +25 -0
- data/test/models/business_support/business_type_test.rb +25 -0
- data/test/models/business_support/location_test.rb +25 -0
- data/test/models/business_support/purpose_test.rb +29 -0
- data/test/models/business_support/sector_test.rb +25 -0
- data/test/models/business_support/stage_test.rb +25 -0
- data/test/models/business_support/support_type_test.rb +25 -0
- data/test/models/business_support_edition_test.rb +186 -0
- data/test/models/campaign_edition_test.rb +90 -0
- data/test/models/curated_list_test.rb +32 -0
- data/test/models/edition_test.rb +826 -0
- data/test/models/fact_check_address_test.rb +36 -0
- data/test/models/help_page_edition_test.rb +38 -0
- data/test/models/licence_edition_test.rb +104 -0
- data/test/models/local_authority_test.rb +113 -0
- data/test/models/local_service_test.rb +199 -0
- data/test/models/local_transaction_edition_test.rb +78 -0
- data/test/models/overview_dashboard_test.rb +47 -0
- data/test/models/simple_smart_answer_edition_test.rb +169 -0
- data/test/models/simple_smart_answer_node_test.rb +134 -0
- data/test/models/simple_smart_answer_option_test.rb +90 -0
- data/test/models/tag_test.rb +92 -0
- data/test/models/time_zone_test.rb +48 -0
- data/test/models/transaction_edition_test.rb +20 -0
- data/test/models/travel_advice_edition_test.rb +480 -0
- data/test/models/user_test.rb +114 -0
- data/test/models/video_edition_test.rb +64 -0
- data/test/models/workflow_actor_test.rb +61 -0
- data/test/models/workflow_test.rb +307 -0
- data/test/test_helper.rb +47 -0
- data/test/traits/attachable_test.rb +143 -0
- data/test/traits/taggable_test.rb +114 -0
- data/test/validators/safe_html_validator_test.rb +86 -0
- data/test/validators/slug_validator_test.rb +42 -0
- metadata +511 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Expectant
|
|
2
|
+
|
|
3
|
+
module ClassMethods
|
|
4
|
+
def expectation_choices
|
|
5
|
+
Hash[Expectation.all.order_by(text: :asc).map {|e| [e.text, e._id.to_s] }]
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
included do
|
|
12
|
+
field :expectation_ids, type: Array, default: []
|
|
13
|
+
field :minutes_to_complete, type: String
|
|
14
|
+
field :uses_government_gateway, type: Boolean
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def expectations
|
|
18
|
+
Expectation.criteria.in(_id: self.expectation_ids)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require "edition"
|
|
2
|
+
require "parted"
|
|
3
|
+
|
|
4
|
+
class GuideEdition < Edition
|
|
5
|
+
include Parted
|
|
6
|
+
|
|
7
|
+
field :video_url, type: String
|
|
8
|
+
field :video_summary, type: String
|
|
9
|
+
|
|
10
|
+
@fields_to_clone = [:video_url, :video_summary]
|
|
11
|
+
|
|
12
|
+
def has_video?
|
|
13
|
+
video_url.present?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def safe_to_preview?
|
|
17
|
+
parts.any? and parts.first.slug.present?
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require "edition"
|
|
2
|
+
|
|
3
|
+
class LicenceEdition < Edition
|
|
4
|
+
|
|
5
|
+
field :licence_identifier, :type => String
|
|
6
|
+
field :licence_short_description, :type => String
|
|
7
|
+
field :licence_overview, :type => String
|
|
8
|
+
field :will_continue_on, :type => String
|
|
9
|
+
field :continuation_link, :type => String
|
|
10
|
+
|
|
11
|
+
GOVSPEAK_FIELDS = Edition::GOVSPEAK_FIELDS + [:licence_overview]
|
|
12
|
+
|
|
13
|
+
validates :licence_identifier, :presence => true
|
|
14
|
+
validate :licence_identifier_unique
|
|
15
|
+
validates_format_of :continuation_link, :with => URI::regexp(%w(http https)), :allow_blank => true
|
|
16
|
+
|
|
17
|
+
@fields_to_clone = [:licence_identifier, :licence_short_description,
|
|
18
|
+
:licence_overview, :will_continue_on, :continuation_link]
|
|
19
|
+
|
|
20
|
+
def whole_body
|
|
21
|
+
[licence_short_description, licence_overview].join("\n\n")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def indexable_content
|
|
25
|
+
"#{super} #{licence_short_description} #{Govspeak::Document.new(licence_overview).to_text}".strip
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
def licence_identifier_unique
|
|
30
|
+
if self.class.without_state('archived').where(:licence_identifier => licence_identifier,
|
|
31
|
+
:panopticon_id.ne => panopticon_id).any?
|
|
32
|
+
errors.add(:licence_identifier, :taken)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require "csv"
|
|
2
|
+
require "local_interaction"
|
|
3
|
+
require "safe_html"
|
|
4
|
+
|
|
5
|
+
class LocalAuthority
|
|
6
|
+
include Mongoid::Document
|
|
7
|
+
|
|
8
|
+
embeds_many :local_interactions
|
|
9
|
+
|
|
10
|
+
field :name, type: String
|
|
11
|
+
field :snac, type: String
|
|
12
|
+
field :local_directgov_id, type: Integer
|
|
13
|
+
field :tier, type: String
|
|
14
|
+
field :contact_address, type: Array
|
|
15
|
+
field :contact_url, type: String
|
|
16
|
+
field :contact_phone, type: String
|
|
17
|
+
field :contact_email, type: String
|
|
18
|
+
|
|
19
|
+
GOVSPEAK_FIELDS = []
|
|
20
|
+
|
|
21
|
+
validates_uniqueness_of :snac
|
|
22
|
+
validates_presence_of :snac, :local_directgov_id, :name, :tier
|
|
23
|
+
validates_with SafeHtml
|
|
24
|
+
|
|
25
|
+
scope :for_snacs, ->(snacs) { any_in(snac: snacs) }
|
|
26
|
+
|
|
27
|
+
def self.find_by_snac(snac)
|
|
28
|
+
for_snacs([snac]).first
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def provides_service?(lgsl_code, lgil_code = nil)
|
|
32
|
+
interactions_for(lgsl_code, lgil_code).any?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def interactions_for(lgsl_code, lgil_code = nil)
|
|
36
|
+
interactions = local_interactions.where(lgsl_code: lgsl_code)
|
|
37
|
+
if lgil_code
|
|
38
|
+
interactions.where(lgil_code: lgil_code)
|
|
39
|
+
else
|
|
40
|
+
interactions
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def preferred_interaction_for(lgsl_code, lgil_code = nil)
|
|
45
|
+
interactions = local_interactions.where(lgsl_code: lgsl_code)
|
|
46
|
+
if lgil_code
|
|
47
|
+
interactions.where(lgil_code: lgil_code).first
|
|
48
|
+
else
|
|
49
|
+
interactions.excludes(
|
|
50
|
+
lgil_code: LocalInteraction::LGIL_CODE_PROVIDING_INFORMATION
|
|
51
|
+
).order_by([:lgil_code, :asc]).first ||
|
|
52
|
+
interactions.where(
|
|
53
|
+
lgil_code: LocalInteraction::LGIL_CODE_PROVIDING_INFORMATION
|
|
54
|
+
).first
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "csv"
|
|
2
|
+
require "safe_html"
|
|
3
|
+
|
|
4
|
+
class LocalInteraction
|
|
5
|
+
include Mongoid::Document
|
|
6
|
+
|
|
7
|
+
LGIL_CODE_PROVIDING_INFORMATION = 8
|
|
8
|
+
|
|
9
|
+
field :lgsl_code, type: Integer
|
|
10
|
+
field :lgil_code, type: Integer
|
|
11
|
+
field :url, type: String
|
|
12
|
+
|
|
13
|
+
GOVSPEAK_FIELDS = []
|
|
14
|
+
|
|
15
|
+
embedded_in :local_authority
|
|
16
|
+
|
|
17
|
+
validates_presence_of :url, :lgil_code, :lgsl_code
|
|
18
|
+
validates_uniqueness_of :lgil_code, :scope => :lgsl_code
|
|
19
|
+
validates_with SafeHtml
|
|
20
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require "csv"
|
|
2
|
+
require "local_authority"
|
|
3
|
+
require "safe_html"
|
|
4
|
+
|
|
5
|
+
class LocalService
|
|
6
|
+
include Mongoid::Document
|
|
7
|
+
|
|
8
|
+
field :description, type: String
|
|
9
|
+
field :lgsl_code, type: Integer
|
|
10
|
+
field :providing_tier, type: Array
|
|
11
|
+
|
|
12
|
+
GOVSPEAK_FIELDS = []
|
|
13
|
+
|
|
14
|
+
validates_presence_of :lgsl_code, :providing_tier
|
|
15
|
+
validates_uniqueness_of :lgsl_code
|
|
16
|
+
validates :providing_tier, inclusion: {
|
|
17
|
+
in: [%w{county unitary}, %w{district unitary}, %w{district unitary county}]
|
|
18
|
+
}
|
|
19
|
+
validates_with SafeHtml
|
|
20
|
+
|
|
21
|
+
def self.find_by_lgsl_code(lgsl_code)
|
|
22
|
+
LocalService.where(lgsl_code: lgsl_code).first
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def preferred_interaction(snac_or_snac_list, lgil_override = nil)
|
|
26
|
+
provider = preferred_provider(snac_or_snac_list)
|
|
27
|
+
provider && provider.preferred_interaction_for(lgsl_code, lgil_override)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def preferred_provider(snac_or_snac_list)
|
|
31
|
+
snac_list = [*snac_or_snac_list]
|
|
32
|
+
providers = LocalAuthority.for_snacs(snac_list)
|
|
33
|
+
select_tier(providers)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def provided_by
|
|
37
|
+
LocalAuthority.where("local_interactions.lgsl_code" => lgsl_code)
|
|
38
|
+
.any_in(tier: providing_tier)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def select_tier(authorities)
|
|
44
|
+
by_tier = Hash[authorities.map {|a| [a.tier, a]}]
|
|
45
|
+
tier = providing_tier.find { |t| by_tier.has_key?(t) }
|
|
46
|
+
tier && by_tier[tier]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require "expectant"
|
|
2
|
+
require "local_service"
|
|
3
|
+
require "edition"
|
|
4
|
+
|
|
5
|
+
class LocalTransactionEdition < Edition
|
|
6
|
+
include Expectant
|
|
7
|
+
|
|
8
|
+
field :lgsl_code, type: Integer
|
|
9
|
+
field :lgil_override, type: Integer
|
|
10
|
+
field :introduction, type: String
|
|
11
|
+
field :more_information, type: String
|
|
12
|
+
|
|
13
|
+
GOVSPEAK_FIELDS = Edition::GOVSPEAK_FIELDS + [:introduction, :more_information]
|
|
14
|
+
|
|
15
|
+
@fields_to_clone = [
|
|
16
|
+
:lgsl_code, :introduction, :more_information,
|
|
17
|
+
:minutes_to_complete, :expectation_ids
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
validate :valid_lgsl_code
|
|
21
|
+
|
|
22
|
+
def valid_lgsl_code
|
|
23
|
+
if ! self.service
|
|
24
|
+
errors.add(:lgsl_code, "#{lgsl_code} not recognised")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def format_name
|
|
29
|
+
"Local transaction"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def search_format
|
|
33
|
+
"transaction"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def service
|
|
37
|
+
LocalService.find_by_lgsl_code(lgsl_code)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def service_provided_by?(snac)
|
|
41
|
+
authority = LocalAuthority.find_by_snac(snac)
|
|
42
|
+
authority && authority.provides_service?(lgsl_code)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def whole_body
|
|
46
|
+
self.introduction
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require "safe_html"
|
|
2
|
+
|
|
3
|
+
class OverviewDashboard
|
|
4
|
+
include Mongoid::Document
|
|
5
|
+
|
|
6
|
+
TOTAL_KEY = "**TOTAL**"
|
|
7
|
+
UNASSIGNED_KEY = "**UNASSIGNED**"
|
|
8
|
+
|
|
9
|
+
field :dashboard_type, type: String
|
|
10
|
+
field :result_group, type: Integer
|
|
11
|
+
field :count, type: Integer
|
|
12
|
+
field :lined_up, type: Integer
|
|
13
|
+
field :draft, type: Integer
|
|
14
|
+
field :amends_needed, type: Integer
|
|
15
|
+
field :in_review, type: Integer
|
|
16
|
+
field :ready, type: Integer
|
|
17
|
+
field :fact_check_received, type: Integer
|
|
18
|
+
field :fact_check, type: Integer
|
|
19
|
+
field :published, type: Integer
|
|
20
|
+
field :archived, type: Integer
|
|
21
|
+
|
|
22
|
+
GOVSPEAK_FIELDS = []
|
|
23
|
+
|
|
24
|
+
validates_with SafeHtml
|
|
25
|
+
end
|
data/app/models/part.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require "safe_html"
|
|
2
|
+
require 'govspeak_smart_quotes_fixer'
|
|
3
|
+
|
|
4
|
+
class Part
|
|
5
|
+
include Mongoid::Document
|
|
6
|
+
|
|
7
|
+
embedded_in :guide_edition
|
|
8
|
+
embedded_in :programme_edition
|
|
9
|
+
embedded_in :business_support_edition
|
|
10
|
+
|
|
11
|
+
scope :in_order, order_by(:order, :asc)
|
|
12
|
+
|
|
13
|
+
field :order, type: Integer
|
|
14
|
+
field :title, type: String
|
|
15
|
+
field :body, type: String
|
|
16
|
+
field :slug, type: String
|
|
17
|
+
field :created_at, type: DateTime, default: lambda { Time.zone.now }
|
|
18
|
+
|
|
19
|
+
GOVSPEAK_FIELDS = [:body]
|
|
20
|
+
|
|
21
|
+
include GovspeakSmartQuotesFixer
|
|
22
|
+
|
|
23
|
+
validates_presence_of :title
|
|
24
|
+
validates_presence_of :slug
|
|
25
|
+
validates_exclusion_of :slug, in: ["video"], message: "Can not be video"
|
|
26
|
+
validates_format_of :slug, with: /^[a-z0-9\-]+$/i
|
|
27
|
+
validates_with SafeHtml
|
|
28
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require "part"
|
|
2
|
+
|
|
3
|
+
module Parted
|
|
4
|
+
def self.included(klass)
|
|
5
|
+
klass.embeds_many :parts
|
|
6
|
+
klass.accepts_nested_attributes_for :parts, allow_destroy: true,
|
|
7
|
+
reject_if: proc { |attrs| attrs["title"].blank? and attrs["body"].blank? }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def build_clone(edition_class=nil)
|
|
11
|
+
new_edition = super
|
|
12
|
+
|
|
13
|
+
# If the new edition is of the same type or another type that has parts,
|
|
14
|
+
# copy over the parts from this edition
|
|
15
|
+
if edition_class.nil? or edition_class.include? Parted
|
|
16
|
+
new_edition.parts = self.parts.map {|p| p.dup }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
new_edition
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def order_parts
|
|
23
|
+
ordered_parts = parts.sort_by { |p| p.order ? p.order : 99999 }
|
|
24
|
+
ordered_parts.each_with_index do |obj, i|
|
|
25
|
+
obj.order = i + 1
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def whole_body
|
|
30
|
+
self.parts.map {|i| %Q{\# #{i.title}\n\n#{i.body}} }.join("\n\n")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "edition"
|
|
2
|
+
require "expectant"
|
|
3
|
+
|
|
4
|
+
class PlaceEdition < Edition
|
|
5
|
+
include Expectant
|
|
6
|
+
|
|
7
|
+
field :introduction, type: String
|
|
8
|
+
field :more_information, type: String
|
|
9
|
+
field :place_type, type: String
|
|
10
|
+
|
|
11
|
+
GOVSPEAK_FIELDS = Edition::GOVSPEAK_FIELDS + [:introduction, :more_information]
|
|
12
|
+
|
|
13
|
+
@fields_to_clone = [:introduction, :more_information, :place_type,
|
|
14
|
+
:expectation_ids]
|
|
15
|
+
|
|
16
|
+
def whole_body
|
|
17
|
+
self.introduction
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require "edition"
|
|
2
|
+
require "parted"
|
|
3
|
+
|
|
4
|
+
class ProgrammeEdition < Edition
|
|
5
|
+
include Parted
|
|
6
|
+
|
|
7
|
+
before_save :setup_default_parts, on: :create
|
|
8
|
+
|
|
9
|
+
@fields_to_clone = []
|
|
10
|
+
|
|
11
|
+
DEFAULT_PARTS = [
|
|
12
|
+
{title: "Overview", slug: "overview"},
|
|
13
|
+
{title: "What you'll get", slug: "what-youll-get"},
|
|
14
|
+
{title: "Eligibility", slug: "eligibility"},
|
|
15
|
+
{title: "How to claim", slug: "how-to-claim"},
|
|
16
|
+
{title: "Further information", slug: "further-information"},
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
def setup_default_parts
|
|
20
|
+
if parts.empty?
|
|
21
|
+
DEFAULT_PARTS.each { |part|
|
|
22
|
+
parts.build(title: part[:title], slug: part[:slug], body: "")
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require "edition"
|
|
2
|
+
require_relative 'simple_smart_answer_edition/node'
|
|
3
|
+
require_relative 'simple_smart_answer_edition/node/option'
|
|
4
|
+
|
|
5
|
+
class SimpleSmartAnswerEdition < Edition
|
|
6
|
+
include Mongoid::Document
|
|
7
|
+
|
|
8
|
+
field :body, type: String
|
|
9
|
+
|
|
10
|
+
embeds_many :nodes, :class_name => "SimpleSmartAnswerEdition::Node"
|
|
11
|
+
|
|
12
|
+
accepts_nested_attributes_for :nodes, allow_destroy: true
|
|
13
|
+
|
|
14
|
+
GOVSPEAK_FIELDS = Edition::GOVSPEAK_FIELDS + [:body]
|
|
15
|
+
@fields_to_clone = [:body]
|
|
16
|
+
|
|
17
|
+
def whole_body
|
|
18
|
+
body
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def build_clone(edition_class=nil)
|
|
22
|
+
new_edition = super(edition_class)
|
|
23
|
+
new_edition.body = self.body
|
|
24
|
+
|
|
25
|
+
if new_edition.is_a?(SimpleSmartAnswerEdition)
|
|
26
|
+
self.nodes.each {|n| new_edition.nodes << n.clone }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
new_edition
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Workaround mongoid conflicting mods error
|
|
34
|
+
# See https://github.com/mongoid/mongoid/issues/1219
|
|
35
|
+
# Override update_attributes so that nested nodes are updated individually.
|
|
36
|
+
# This get around the problem of mongoid issuing a query with conflicting modifications
|
|
37
|
+
# to the same document.
|
|
38
|
+
alias_method :original_update_attributes, :update_attributes
|
|
39
|
+
|
|
40
|
+
def update_attributes(attributes)
|
|
41
|
+
if nodes_attrs = attributes.delete(:nodes_attributes)
|
|
42
|
+
nodes_attrs.each do |index, node_attrs|
|
|
43
|
+
if node_id = node_attrs['id']
|
|
44
|
+
node = nodes.find(node_id)
|
|
45
|
+
if destroy_in_attrs?(node_attrs)
|
|
46
|
+
node.destroy
|
|
47
|
+
else
|
|
48
|
+
node.update_attributes(node_attrs)
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
nodes << Node.new(node_attrs) unless destroy_in_attrs?(node_attrs)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
original_update_attributes(attributes)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def initial_node
|
|
60
|
+
self.nodes.first
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def destroy_in_attrs?(attrs)
|
|
64
|
+
attrs['_destroy'] == '1'
|
|
65
|
+
end
|
|
66
|
+
end
|