docbrown/app/models/chat_channel.rb
Jacob Herrington 099b188530 Rename uncommunicative variables (#3890)
* Clarify uncommunicative variables in labor classes

Single letter variable names are largely a question of preference, in
some cases I think that convention mitigates the opaque nature of single
letter variable names (e.g., e for error, i for index, etc).

However, in some cases they can be unclear and there isn't much reason
to use single letter variables unless for some reason character length is
really important.

In this case, I would prefer clarity in variable names over brevity of
code so I've used Reek to identify short variable names and I'm changing
them.

It's pretty boring, but hopefully incremental code love changes like
this one add up and improve readability and accessibility for those
interested in reading this codebase.

* Remove commented code from 2 years ago

* Clarify uncommunicative naming in services classes

There is some context for this change in 6b81880f

* Clarify uncommunicative naming in models

There is some context for this change in 6b81880f

* Clarify uncommunicative naming in liquid_tags

There is some context for this change in 6b81880f
2019-09-02 13:05:07 -04:00

165 lines
5 KiB
Ruby

class ChatChannel < ApplicationRecord
include AlgoliaSearch
attr_accessor :current_user, :usernames_string
has_many :messages
has_many :chat_channel_memberships, dependent: :destroy
has_many :users, through: :chat_channel_memberships
has_many :active_memberships, -> { where status: "active" }, class_name: "ChatChannelMembership", inverse_of: :chat_channel
has_many :pending_memberships, -> { where status: "pending" }, class_name: "ChatChannelMembership", inverse_of: :chat_channel
has_many :rejected_memberships, -> { where status: "rejected" }, class_name: "ChatChannelMembership", inverse_of: :chat_channel
has_many :mod_memberships, -> { where role: "mod" }, class_name: "ChatChannelMembership", inverse_of: :chat_channel
has_many :active_users, through: :active_memberships, class_name: "User", source: :user
has_many :pending_users, through: :pending_memberships, class_name: "User", source: :user
has_many :rejected_users, through: :rejected_memberships, class_name: "User", source: :user
has_many :mod_users, through: :mod_memberships, class_name: "User", source: :user
validates :channel_type, presence: true, inclusion: { in: %w[open invite_only direct] }
validates :status, presence: true, inclusion: { in: %w[active inactive blocked] }
validates :slug, uniqueness: true, presence: true
algoliasearch index_name: "SecuredChatChannel_#{Rails.env}" do
attribute :id, :viewable_by, :slug, :channel_type,
:channel_name, :last_message_at, :status,
:messages_count, :channel_human_names, :channel_mod_ids, :pending_users_select_fields,
:description
searchableAttributes %i[channel_name channel_slug channel_human_names]
attributesForFaceting ["filterOnly(viewable_by)", "filterOnly(status)", "filterOnly(channel_type)"]
ranking ["desc(last_message_at)"]
end
before_destroy :remove_from_index!
def open?
channel_type == "open"
end
def direct?
channel_type == "direct"
end
def invite_only?
channel_type == "invite_only"
end
def clear_channel
messages.find_each(&:destroy!)
Pusher.trigger(pusher_channels, "channel-cleared", { chat_channel_id: id }.to_json)
true
rescue Pusher::Error => e
logger.info "PUSHER ERROR: #{e.message}"
end
def has_member?(user)
active_users.include?(user)
end
def last_opened_at(user = nil)
user ||= current_user
chat_channel_memberships.where(user_id: user.id).pluck(:last_opened_at).first
end
def self.create_with_users(users, channel_type = "direct", contrived_name = "New Channel")
raise "Invalid direct channel" if users.size != 2 && channel_type == "direct"
if channel_type == "direct"
usernames = users.map(&:username).sort
contrived_name = "Direct chat between " + usernames.join(" and ")
slug = usernames.join("/")
else
slug = contrived_name.to_s.parameterize + "-" + rand(100_000).to_s(26)
end
channel = ChatChannel.find_by(slug: slug)
if channel
raise "Blocked channel" if channel.status == "blocked"
channel.status = "active"
channel.save
else
channel = create(
channel_type: channel_type,
channel_name: contrived_name,
slug: slug,
last_message_at: 1.week.ago,
status: "active",
)
channel.add_users(users)
channel.index!
channel.chat_channel_memberships.map(&:index!)
end
channel
end
def add_users(users)
Array(users).each do |user|
ChatChannelMembership.create!(user_id: user.id, chat_channel_id: id)
end
end
def pusher_channels
if invite_only?
"presence-channel-#{id}"
elsif open?
"open-channel-#{id}"
else
chat_channel_memberships.pluck(:user_id).map { |id| "private-message-notifications-#{id}" }
end
end
def adjusted_slug(user = nil, caller_type = "receiver")
user ||= current_user
if direct? && caller_type == "receiver"
"@" + slug.gsub("/#{user.username}", "").gsub("#{user.username}/", "")
elsif caller_type == "sender"
"@" + user.username
else
slug
end
end
def viewable_by
active_memberships.pluck(:user_id)
end
def messages_count
messages.size
end
def channel_human_names
active_memberships.
order("last_opened_at DESC").limit(5).includes(:user).map do |membership|
membership.user.name
end
end
def channel_users
# Purely for algolia indexing
obj = {}
active_memberships.
order("last_opened_at DESC").includes(:user).each do |membership|
obj[membership.user.username] = user_obj(membership)
end
obj
end
def channel_mod_ids
mod_users.pluck(:id)
end
def user_obj(membership)
{
profile_image: ProfileImage.new(membership.user).get(90),
darker_color: membership.user.decorate.darker_color,
name: membership.user.name,
last_opened_at: membership.last_opened_at,
username: membership.user.username,
id: membership.user_id
}
end
def pending_users_select_fields
pending_users.select(:id, :username, :name, :updated_at)
end
end