docbrown/app/models/chat_channel.rb
Ernesto Tagwerker 9ea3a8c67d
Upgrade to Rails 6.0 (#7658)
* Add dual booting logic to Gemfile

This might be helpful for the Rails 6.0 upgrade project.

* Add more than one gemfile to Travis' configuration

We want to see how the application behaves with more than one Rails versions:

- Gemfile -> Rails 5.2
- Gemfile.next -> Rails 6.0

This will help us figure out what needs to be addressed before migrating to Rails 6.0.

If you want to read more about this technique (dual booting) you can check out this page: https://www.fastruby.io/blog/upgrade-rails/dual-boot/dual-boot-with-rails-6-0-beta.html

* Fix joins

* Upgrade Gemfile.next.lock

* Make sure we're installing the correct versions of gems

* Add Rails 6 notes

* Update rubocop in Gemfile.next.lock

* Fix organization spec

* Fix page_views_spec

* Add Rails 6 and run rails app:update

* Remove some tricks

* Remove Gemfile.next for now

* Fix .content_type deprecation

* Fix deprecation of .where.not NAND/NOR behavior

* Fix deprecation of parameterized emails

* Fix specs

* Remove next flag for now

* Fix spec (hopefully)

* Add wait_for_javascript

* Fix spec, thanks @maestromac!

* Try without wait for javascript hack

* Remove unnecessary bin/update

* Remove file that snuck in the rebase

* Update the vendored gems

* Replace migrate+db:setup with db:prepare

* Update vendored gems

* Fix Gemfile.lock and update vendored stuff

* Fix Gemfile.lock to be the same as master's minus the changes

Co-authored-by: rhymes <rhymesete@gmail.com>
2020-06-04 11:54:25 +02:00

197 lines
6.4 KiB
Ruby

class ChatChannel < ApplicationRecord
attr_accessor :current_user, :usernames_string
CHANNEL_TYPES = %w[open invite_only direct].freeze
STATUSES = %w[active inactive blocked].freeze
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 :requested_memberships, -> { where status: "joining_request" }, 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: CHANNEL_TYPES }
validates :status, presence: true, inclusion: { in: STATUSES }
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 invalid_direct_channel?(users, channel_type)
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
def invalid_direct_channel?(users, channel_type)
(users.size != 2 || users.map(&:id).uniq.count < 2) && channel_type == "direct"
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.with(membership: existing_membership, inviter: inviter).channel_invite_email.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.with(membership: membership, inviter: inviter).channel_invite_email.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