docbrown/app/models/chat_channel.rb
rhymes a2893056b6
Routine rubocop fixes (#7356)
* rubocop -a

* Fix stuff

* rubocop -a again

* autocorrect
2020-04-17 15:48:39 +02:00

189 lines
6 KiB
Ruby

class ChatChannel < ApplicationRecord
attr_accessor :current_user, :usernames_string
has_many :messages, dependent: :destroy
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
validates :description, length: { maximum: 200 }, allow_blank: true
def open?
channel_type == "open"
end
def direct?
channel_type == "direct"
end
def invite_only?
channel_type == "invite_only"
end
def group?
channel_type != "direct"
end
def private_org_channel?
channel_name.to_s.ends_with?(" private group chat") # e.g. @devteam private group chat
end
def clear_channel
messages.destroy_all
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
class << self
def create_with_users(users:, channel_type: "direct", contrived_name: "New Channel", membership_role: "member")
raise "Invalid direct channel" if users.size != 2 && channel_type == "direct"
usernames = users.map(&:username).sort
slug = channel_type == "direct" ? usernames.join("/") : contrived_name.to_s.parameterize + "-" + rand(100_000).to_s(26)
contrived_name = "Direct chat between " + usernames.join(" and ") if channel_type == "direct"
channel = find_or_create_chat_channel(channel_type, slug, contrived_name)
if channel_type == "direct"
channel.add_users(users)
else
channel.invite_users(users: users, membership_role: membership_role)
end
channel
end
def find_or_create_chat_channel(channel_type, slug, contrived_name)
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",
)
end
channel
end
end
def add_users(users)
Array(users).each do |user|
ChatChannelMembership.find_or_create_by!(user_id: user.id, chat_channel_id: id)
end
end
def invite_users(users:, membership_role: "member", inviter: nil)
invitation_sent = 0
Array(users).each do |user|
existing_membership = ChatChannelMembership.find_by(user_id: user.id, chat_channel_id: id)
if existing_membership.present? && %w[active pending].exclude?(existing_membership.status)
if existing_membership.update(status: "pending", role: membership_role)
NotifyMailer.channel_invite_email(existing_membership, inviter).deliver_later
invitation_sent += 1
end
else
membership = ChatChannelMembership.create(user_id: user.id, chat_channel_id: id, role: membership_role, status: "pending")
if membership.persisted?
NotifyMailer.channel_invite_email(membership, inviter).deliver_later
invitation_sent += 1
end
end
end
invitation_sent
end
def remove_user(user)
chat_channel_memberships.where(user: user).destroy_all
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 channel_users_ids
chat_channel_memberships.pluck(:user_id)
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 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
obj = {}
relation = active_memberships.includes(:user).select(:id, :user_id, :last_opened_at)
relation.order(last_opened_at: :desc).each do |membership|
obj[membership.user.username] = user_obj(membership)
end
obj
end
def channel_mod_ids
mod_users.pluck(:id)
end
def pending_users_select_fields
pending_users.select(:id, :username, :name, :updated_at)
end
private
def user_obj(membership)
{
profile_image: ProfileImage.new(membership.user).get(width: 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
end