<commit_before>#  This is a generic versioned wiki, primarily used by the WikiPage,
#  but also used directly sometimes by other classes (like for Group's
#  landing page wiki's).
#
#
#     create_table "wikis", :force => true do |t|
#       t.text     "body"
#       t.text     "body_html"
#       t.datetime "updated_at"
#       t.integer  "user_id",       :limit => 11
#       t.integer  "version",       :limit => 11
#       t.text     "raw_structure"
#     end
#
#     add_index "wikis", ["user_id"], :name => "index_wikis_user_id"
#

##

# requirements/ideas:
# 1. nothing should get saved until we say save!
# 2. updating body automatically updates html and structure
# 3. wiki should never get saved with body/body products mismatch
# 4. loaded wiki should see only the latest body products, if body was updated from outside
class Wiki < ActiveRecord::Base
  include WikiExtension::Locking
  include WikiExtension::Sections
  include WikiExtension::Versioning

  # a wiki can be used in multiple places: pages or profiles
  has_many :pages, :as => :data
  has_one :profile
  has_one :group, :through => :profile, :source => :entity, :source_type => 'Group'
  attr_accessor :private # marks private group wikis during creation

  has_one :section_locks, :class_name => "WikiLock", :dependent => :destroy

  serialize :raw_structure, Hash

  acts_as_versioned :if => :create_new_version? do
    def self.included(base)
      base.belongs_to :user
      base.serialize :raw_structure, Hash
    end
  end
  # versions are so tightly coupled that wiki.versions should always be up to date
  # this must be declared after acts_as_versioned, since AAV declares its own after_save
  # callback that create versions
  # locks should reloaded too, since some locks may become invalid (because of section heading changes)
  after_save :reload_versions_and_locks

  # only save a new version if the body has changed
  # need more control than composed of
  attr_reader :structure

  before_save :update_body_html_and_structure
  before_save :update_latest_version_record

  # constant for length to show preview rather than full wiki
  PREVIEW_CHARS = 500

  # section locks should never be nil
  alias_method :existing_section_locks, :section_locks
  def section_locks(force_reload = false)
    # current section_locks or create a new one if it doesn't exist
    locks = (existing_section_locks(force_reload) || build_section_locks(:wiki => self))
    # section_locks should always have self as its wiki instance
    # in case self.body is updated (and section names get changed)
    locks.wiki = self
    locks
  end

  def label
    return :create_a_new_thing.t(:thing => 'Wiki') if self.new_record?
    if self.profile
      self.profile.public? ? :public_group_wiki : :private_group_wiki
    else
      :page_wiki
    end
  end

  def update_document!(user, current_version, text)
    check_and_unlock_section!(:document, user, current_version)
    self.user = user
    self.body = text
    self.save!
  end

  # similar to update_attributes!, but only for text
  # this method will perform unlocking and will check version numbers
  # it will skip version_checking if current_version is nil (useful for section editing)
  def update_section!(section, user, current_version, text)
    check_and_unlock_section!(section, user, current_version)
    self.user = user
    save_section!(section, text)
  end

  # updating body will invalidate body_html
  # reading body_html or saving this wiki
  # will regenerate body_html from body if render_body_html_proc is available
  def body=(body)
    write_attribute(:body, body)
    # invalidate body_html and raw_structure
    if body_changed?
      write_attribute(:body_html, nil)
      write_attribute(:raw_structure, nil)
      @structure = nil
    end
  end

  def clear_html
    write_attribute(:body_html, nil)
  end

  # will render if not up to date
  def body_html
    update_body_html_and_structure

    read_attribute(:body_html).html_safe
  end

  def preview_html
    render_preview(PREVIEW_CHARS).html_safe
  end

  # will calculate structure if not up to date
  # calculating structure will also update body_html
  def raw_structure
    update_body_html_and_structure

    read_attribute(:raw_structure) || write_attribute(:raw_structure, {})
  end

  def structure
    @structure ||= WikiExtension::WikiStructure.new(raw_structure, body.to_s)
  end

  # sets the block used for rendering the body to html<commit_msg>protect against preview being nil for .html_safe<commit_after>#  This is a generic versioned wiki, primarily used by the WikiPage,
#  but also used directly sometimes by other classes (like for Group's
#  landing page wiki's).
#
#
#     create_table "wikis", :force => true do |t|
#       t.text     "body"
#       t.text     "body_html"
#       t.datetime "updated_at"
#       t.integer  "user_id",       :limit => 11
#       t.integer  "version",       :limit => 11
#       t.text     "raw_structure"
#     end
#
#     add_index "wikis", ["user_id"], :name => "index_wikis_user_id"
#

##

# requirements/ideas:
# 1. nothing should get saved until we say save!
# 2. updating body automatically updates html and structure
# 3. wiki should never get saved with body/body products mismatch
# 4. loaded wiki should see only the latest body products, if body was updated from outside
class Wiki < ActiveRecord::Base
  include WikiExtension::Locking
  include WikiExtension::Sections
  include WikiExtension::Versioning

  # a wiki can be used in multiple places: pages or profiles
  has_many :pages, :as => :data
  has_one :profile
  has_one :group, :through => :profile, :source => :entity, :source_type => 'Group'
  attr_accessor :private # marks private group wikis during creation

  has_one :section_locks, :class_name => "WikiLock", :dependent => :destroy

  serialize :raw_structure, Hash

  acts_as_versioned :if => :create_new_version? do
    def self.included(base)
      base.belongs_to :user
      base.serialize :raw_structure, Hash
    end
  end
  # versions are so tightly coupled that wiki.versions should always be up to date
  # this must be declared after acts_as_versioned, since AAV declares its own after_save
  # callback that create versions
  # locks should reloaded too, since some locks may become invalid (because of section heading changes)
  after_save :reload_versions_and_locks

  # only save a new version if the body has changed
  # need more control than composed of
  attr_reader :structure

  before_save :update_body_html_and_structure
  before_save :update_latest_version_record

  # constant for length to show preview rather than full wiki
  PREVIEW_CHARS = 500

  # section locks should never be nil
  alias_method :existing_section_locks, :section_locks
  def section_locks(force_reload = false)
    # current section_locks or create a new one if it doesn't exist
    locks = (existing_section_locks(force_reload) || build_section_locks(:wiki => self))
    # section_locks should always have self as its wiki instance
    # in case self.body is updated (and section names get changed)
    locks.wiki = self
    locks
  end

  def label
    return :create_a_new_thing.t(:thing => 'Wiki') if self.new_record?
    if self.profile
      self.profile.public? ? :public_group_wiki : :private_group_wiki
    else
      :page_wiki
    end
  end

  def update_document!(user, current_version, text)
    check_and_unlock_section!(:document, user, current_version)
    self.user = user
    self.body = text
    self.save!
  end

  # similar to update_attributes!, but only for text
  # this method will perform unlocking and will check version numbers
  # it will skip version_checking if current_version is nil (useful for section editing)
  def update_section!(section, user, current_version, text)
    check_and_unlock_section!(section, user, current_version)
    self.user = user
    save_section!(section, text)
  end

  # updating body will invalidate body_html
  # reading body_html or saving this wiki
  # will regenerate body_html from body if render_body_html_proc is available
  def body=(body)
    write_attribute(:body, body)
    # invalidate body_html and raw_structure
    if body_changed?
      write_attribute(:body_html, nil)
      write_attribute(:raw_structure, nil)
      @structure = nil
    end
  end

  def clear_html
    write_attribute(:body_html, nil)
  end

  # will render if not up to date
  def body_html
    update_body_html_and_structure

    read_attribute(:body_html).html_safe
  end

  def preview_html
    render_preview(PREVIEW_CHARS).try.html_safe
  end

  # will calculate structure if not up to date
  # calculating structure will also update body_html
  def raw_structure
    update_body_html_and_structure

    read_attribute(:raw_structure) || write_attribute(:raw_structure, {})
  end

  def structure
    @structure ||= WikiExtension::WikiStructure.new(raw_structure, body.to_s)
  end

  # sets the block used for rendering the body to html
{'fraction_non_alphanumeric': 0.07097563688953165, 'fraction_numerical': 0.002447435754811436, 'mean_word_length': 3.7844598190526875, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '871946', 'n_tokens_mistral': 2721, 'n_tokens_neox': 2591, 'n_words': 921}