require "workflow" require "fact_check_address" class SpecialistDocumentEdition include Mongoid::Document include Mongoid::Timestamps include Workflow field :document_id, type: String field :version_number, type: Integer, default: 1 field :sibling_in_progress, type: Integer, default: nil field :business_proposition, type: Boolean, default: false field :title, type: String field :created_at, type: DateTime, default: lambda { Time.zone.now } field :overview, type: String field :alternative_title, type: String field :slug, type: String field :section, type: String field :department, type: String field :rejected_count, type: Integer, default: 0 field :tags, type: String field :assignee, type: String field :creator, type: String field :publisher, type: String field :archiver, type: String field :summary, type: String field :body, type: String field :opened_date, type: Date field :closed_date, type: Date field :case_type, type: String field :case_state, type: String field :market_sector, type: String field :outcome_type, type: String GOVSPEAK_FIELDS = Edition::GOVSPEAK_FIELDS + [:body] def whole_body self.body end belongs_to :assigned_to, class_name: "User" scope :lined_up, where(state: "lined_up") scope :draft, where(state: "draft") scope :amends_needed, where(state: "amends_needed") scope :in_review, where(state: "in_review") scope :fact_check, where(state: "fact_check") scope :fact_check_received, where(state: "fact_check_received") scope :ready, where(state: "ready") scope :published, where(state: "published") scope :archived, where(state: "archived") scope :in_progress, where(:state.nin => ["archived", "published"]) scope :assigned_to, lambda { |user| if user where(assigned_to_id: user.id) else where(:assigned_to_id.exists => false) end } validates :title, presence: true validates :summary, presence: true validates :body, presence: true validates :opened_date, presence: true validates :market_sector, presence: true validates :case_type, presence: true validates :case_state, presence: true validates :version_number, presence: true validates :document_id, presence: true validates_with SafeHtml index "assigned_to_id" index "document_id" index "state" class << self; attr_accessor :fields_to_clone end @fields_to_clone = [] alias_method :admin_list_title, :title def series SpecialistDocumentEdition.where(document_id: document_id) end def history series.order([:version_number, :desc]) end def siblings series.excludes(id: id) end def previous_siblings siblings.where(:version_number.lt => version_number) end def subsequent_siblings siblings.where(:version_number.gt => version_number) end def latest_edition? subsequent_siblings.empty? end def published_edition series.where(state: "published").order(version_number: "desc").first end def previous_published_edition series.where(state: "published").order(version_number: "desc").second end def in_progress_sibling subsequent_siblings.in_progress.order(version_number: "desc").first end def can_create_new_edition? subsequent_siblings.in_progress.empty? end def meta_data PublicationMetadata.new self end def fact_check_email_address FactCheckAddress.new.for_edition(self) end def get_next_version_number latest_version = series.order(version_number: "desc").first.version_number latest_version + 1 end def indexable_content respond_to?(:parts) ? indexable_content_with_parts : indexable_content_without_parts end def indexable_content_without_parts if respond_to?(:body) "#{alternative_title} #{Govspeak::Document.new(body).to_text}".strip else alternative_title end end def indexable_content_with_parts content = indexable_content_without_parts return content unless published_edition parts.inject([content]) { |acc, part| acc.concat([part.title, Govspeak::Document.new(part.body).to_text]) }.compact.join(" ").strip end # If the new clone is of the same type, we can copy all its fields over; if # we are changing the type of the edition, any fields other than the base # fields will likely be meaningless. def fields_to_copy(edition_class) edition_class == self.class ? self.class.fields_to_clone : [] end def build_clone(edition_class=nil) unless state == "published" raise "Cloning of non published edition not allowed" end unless can_create_new_edition? raise "Cloning of a published edition when an in-progress edition exists is not allowed" end edition_class = self.class unless edition_class new_edition = edition_class.new(title: self.title, version_number: get_next_version_number) real_fields_to_merge = fields_to_copy(edition_class) + [:panopticon_id, :overview, :alternative_title, :slug, :section, :department] real_fields_to_merge.each do |attr| new_edition[attr] = read_attribute(attr) end if edition_class == AnswerEdition and %w(GuideEdition ProgrammeEdition TransactionEdition).include?(self.class.name) new_edition.body = whole_body end if edition_class == TransactionEdition and %w(AnswerEdition GuideEdition ProgrammeEdition).include?(self.class.name) new_edition.more_information = whole_body end if edition_class == GuideEdition and self.is_a?(AnswerEdition) new_edition.parts.build(title: "Part One", body: whole_body, slug: "part-one") end new_edition end def self.find_or_create_from_panopticon_data(panopticon_id, importing_user, api_credentials) existing_publication = Edition.where(panopticon_id: panopticon_id) .order_by([:version_number, :desc]).first return existing_publication if existing_publication raise "Artefact not found" unless metadata = Artefact.find(panopticon_id) importing_user.create_edition(metadata.kind.to_sym, panopticon_id: metadata.id, slug: metadata.slug, title: metadata.name, section: metadata.section, department: metadata.department, business_proposition: metadata.business_proposition) end def self.find_and_identify(slug, edition) scope = where(slug: slug) if edition.present? and edition == "latest" scope.order_by(:version_number).last elsif edition.present? scope.where(version_number: edition).first else scope.where(state: "published").order_by(:created_at).last end end def panopticon_uri Plek.current.find("panopticon") + "/artefacts/" + (panopticon_id || slug).to_s end def format self.class.to_s.gsub("Edition", "") end def format_name format end def has_video? false end def safe_to_preview? true end def has_sibling_in_progress? ! sibling_in_progress.nil? end # Stop broadcasting a delete message unless there are no siblings. def broadcast_action(callback_action) unless callback_action == "destroyed" and self.siblings.any? super(callback_action) end end def was_published previous_siblings.all.each(&:archive) notify_siblings_of_published_edition end def update_from_artefact(artefact) self.title = artefact.name unless published? self.slug = artefact.slug self.section = artefact.section self.department = artefact.department self.business_proposition = artefact.business_proposition self.save! end def artefact Artefact.find(panopticon_id) end end