Wednesday, July 15, 2026 4:00:19 AM
> community.rb
# frozen_string_literal: true

module ESM
  class Community < ApplicationRecord
    # =============================================================================
    # INITIALIZE
    # =============================================================================

    ALPHABET = ("a".."z").to_a.freeze

    # =============================================================================
    # DATA STRUCTURE
    # =============================================================================

    attribute :public_id, :uuid
    attribute :community_id, :string
    attribute :community_name, :text
    attribute :guild_id, :string
    attribute :logging_channel_id, :string
    attribute :log_reconnect_event, :boolean, default: false
    attribute :log_xm8_event, :boolean, default: true
    attribute :log_discord_log_event, :boolean, default: true
    attribute :player_mode_enabled, :boolean, default: true
    attribute :territory_admin_ids, :json, default: []
    attribute :dashboard_access_role_ids, :json, default: []
    attribute :command_prefix, :string, default: nil
    attribute :welcome_message_enabled, :boolean, default: true
    attribute :welcome_message, :string, default: ""
    attribute :allow_v2_servers, :boolean, default: false
    attribute :icon_url, :string
    attribute :created_at, :datetime
    attribute :updated_at, :datetime

    alias_attribute :name, :community_name

    # =============================================================================
    # ASSOCIATIONS
    # =============================================================================

    belongs_to :owner_user, class_name: "User", optional: true

    has_many :command_configurations, dependent: :destroy
    has_many :cooldowns, dependent: :destroy
    has_many :id_defaults, class_name: "CommunityDefault", dependent: :destroy
    has_many :notifications, dependent: :destroy
    has_many :servers, dependent: :destroy
    has_many :user_aliases, dependent: :nullify
    has_many :user_defaults, dependent: :nullify
    has_many :user_notification_routes, foreign_key: :destination_community_id, dependent: :destroy

    # =============================================================================
    # VALIDATIONS
    # =============================================================================

    # =============================================================================
    # CALLBACKS
    # =============================================================================

    before_create :generate_community_id
    before_create :generate_public_id
    after_create :create_command_configurations
    after_create :create_notifications

    # =============================================================================
    # SCOPES
    # =============================================================================

    scope :with_community_id, ->(id) { where("#{table_name}.community_id ilike ?", id) }

    scope(:by_community_id, lambda do |id|
      includes(:servers).with_community_id(id)
    end)

    scope :player_mode_enabled, -> { where(player_mode_enabled: true) }
    scope :player_mode_disabled, -> { where(player_mode_enabled: false) }

    # =============================================================================
    # CLASS METHODS
    # =============================================================================

    def self.correct(id)
      checker = DidYouMean::SpellChecker.new(dictionary: community_ids)
      checker.correct(id)
    end

    def self.find_by_community_id(id)
      by_community_id(id).first
    end

    def self.find_by_guild_id(id)
      includes(:servers).order(:guild_id).where(guild_id: id).first
    end

    def self.find_by_server_id(id)
      return if id.blank?

      joins(:servers).order(:guild_id).where(servers: {server_id: id}).first
    end

    def self.from_discord(discord_server)
      return if discord_server.nil?

      community = order(:guild_id).where(guild_id: discord_server.id).first_or_initialize
      community.update!(community_name: discord_server.name, icon_url: discord_server.icon_url)
      community
    end

    # =============================================================================
    # INSTANCE METHODS
    # =============================================================================

    private

    def generate_community_id
      return if community_id.present?

      count = 0
      new_id = nil

      loop do
        # Attempt to generate an id. Top rated comment from this answer: https://stackoverflow.com/a/88341
        new_id = ALPHABET.sample(4).join
        count += 1

        # Our only saviors
        break if count > 10_000
        break if self.class.find_by_community_id(new_id).nil?
      end

      # Yup. Add to the community_ids so our spell checker works
      self.class.community_ids << new_id
      self.community_id = new_id
    end

    def generate_public_id
      return if public_id.present?

      self.public_id = SecureRandom.uuid
    end

    def create_command_configurations
      configurations = ESM::Command.configurations.map { |c| c.merge(community_id: id) }
      ESM::CommandConfiguration.import(configurations)
    end

    def create_notifications
      ESM::Notification::DEFAULTS.each do |category, notifications|
        notifications =
          notifications.map do |notification|
            {
              public_id: SecureRandom.uuid,
              community_id: id,
              notification_type: notification["type"],
              notification_title: notification["title"],
              notification_description: notification["description"],
              notification_color: notification["color"],
              notification_category: category
            }
          end

        ESM::Notification.import(notifications)
      end
    end
  end
end
All opinions represented herein are my own
- © 2024 - 2026 itsthedevman
- build 43aa0d7