You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: channel.rb
    path of file: ./repos/discourse/plugins/chat/app/models/chat
    
    the code of the file until where you have to start completion: # frozen_string_literal: true

module Chat
  class Channel < ActiveRecord::Base
    include Trashable
    include TypeMappable

    # TODO (martin) Remove once we are using last_message instead,
    # should be around August 2023.
    self.ignored_columns = %w[last_message_sent_at]
    self.table_name = "chat_channels"

    belongs_to :chatable, polymorphic: true
    belongs_to :direct_message,
               class_name: "Chat::DirectMessage",
               foreign_key: :chatable_id,
               inverse_of: :direct_message_channel,
               optional: true

    has_many :chat_messages, class_name: "Chat::Message", foreign_key: :chat_channel_id
    has_many :user_chat_channel_memberships,
             class_name: "Chat::UserChatChannelMembership",
             foreign_key: :chat_channel_id
    has_many :threads, class_name: "Chat::Thread", foreign_key: :channel_id
    has_one :chat_channel_archive, class_name: "Chat::ChannelArchive", foreign_key: :chat_channel_id
    belongs_to :last_message,
               class_name: "Chat::Message",
               foreign_key: :last_message_id,
               optional: true

    def last_message
      super || NullMessage.new
    end

    enum :status,
    
      def sti_class_mapping =
        {
          "CategoryChannel" => Chat::CategoryChannel,
          "DirectMessageChannel" => Chat::DirectMessageChannel,
        }

      def polymorphic_class_mapping = { "DirectMessage" => Chat::DirectMessage }

      def editable_statuses
        statuses.filter { |k, _| !%w[read_only archived].include?(k) }
      end

      def public_channel_chatable_types
        %w[Category]
      end

      def direct_channel_chatable_types
        %w[DirectMessage]
      end

      def chatable_types
        public_channel_chatable_types + direct_channel_chatable_types
      end

      def find_by_id_or_slug(id)
        with_categories.find_by(
          "chat_channels.id = :id OR categories.slug = :slug OR chat_channels.slug = :slug",
          id: Integer(id, exception: false),
          slug: id.to_s.downcase,
        )
      end
    end

    statuses.keys.each do |status|
      define_method("#{status}!") { |acting_user| change_status(acting_user, status.to_sym) }
    end

    %i[
      category_channel?
      direct_message_channel?
      public_channel?
      chatable_has_custom_fields?
      read_restricted?
    ].each { |name| define_method(name) { false } }

    %i[allowed_user_ids allowed_group_ids chatable_url].each { |name| define_method(name) { nil } }

    def ensure_slug_ok
      if self.slug.present?
        # if we don't unescape it first we strip the % from the encoded version
        slug = SiteSetting.slug_generation_method == "encoded" ? CGI.unescape(self.slug) : self.slug
        self.slug = Slug.for(slug, "", method: :encoded)

        if self.slug.blank?
          errors.add(:slug, :invalid)
        elsif SiteSetting.slug_generation_method == "ascii" && !CGI.unescape(self.slug).ascii_only?
          errors.add(:slug, I18n.t("chat.category_channel.errors.slug_contains_non_ascii_chars"))
        elsif duplicate_slug?
          errors.add(:slug, I18n.t("chat.category_channel.errors.is_already_in_use"))
        end
      end
    end