* Optimization:Dont Notify of Channel Leavings * Add specs and dont send pusher notifications or mark chat channel as unread for left or removed chat actions
289 lines
12 KiB
Ruby
289 lines
12 KiB
Ruby
class ChatChannelMembershipsController < ApplicationController
|
|
before_action :authenticate_user!
|
|
after_action :verify_authorized, except: %w[join_channel request_details]
|
|
|
|
include MessagesHelper
|
|
|
|
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
|
|
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
|
|
|
|
def index
|
|
skip_authorization
|
|
memberships = current_user.chat_channel_memberships.includes(:chat_channel)
|
|
@pending_invites = memberships.filter_by_status("pending")
|
|
end
|
|
|
|
def find_by_chat_channel_id
|
|
@membership = ChatChannelMembership.where(chat_channel_id: params[:chat_channel_id],
|
|
user_id: current_user.id).first!
|
|
authorize @membership
|
|
render json: @membership.to_json(
|
|
only: %i[id status viewable_by chat_channel_id last_opened_at],
|
|
methods: %i[channel_text channel_last_message_at channel_status channel_username
|
|
channel_type channel_text channel_name channel_image channel_modified_slug channel_messages_count],
|
|
)
|
|
end
|
|
|
|
def chat_channel_info
|
|
@membership = ChatChannelMembership.find(params[:id])
|
|
authorize @membership
|
|
@channel = @membership.chat_channel
|
|
invite_cache_key = "chat-channel-invite-#{@channel.id}"
|
|
invitation_slug = Rails.cache.fetch(invite_cache_key, expires_in: 80.hours) do
|
|
"invitation-link-#{SecureRandom.hex(3)}"
|
|
end
|
|
@invitation_link = "/join_channel_invitation/#{@channel.slug}?invitation_slug=#{invitation_slug}"
|
|
end
|
|
|
|
def create_membership_request
|
|
chat_channel = ChatChannel.find_by(id: channel_membership_params[:chat_channel_id])
|
|
authorize chat_channel, :update?
|
|
usernames = channel_membership_params[:invitation_usernames].split(",").map do |username|
|
|
username.strip.delete("@")
|
|
end
|
|
users = User.where(username: usernames)
|
|
invitations_sent = chat_channel.invite_users(users: users, membership_role: "member", inviter: current_user)
|
|
message = if invitations_sent.zero?
|
|
"No invitations sent. Check for username typos."
|
|
else
|
|
"#{invitations_sent} #{'invitation'.pluralize(invitations_sent)} sent."
|
|
end
|
|
|
|
render json: { success: true, message: message, data: {} }, status: :ok
|
|
end
|
|
|
|
def join_channel
|
|
membership_params = params[:chat_channel_membership]
|
|
chat_channel = ChatChannel.find(membership_params[:chat_channel_id])
|
|
existing_membership = ChatChannelMembership.find_by(user_id: current_user.id, chat_channel_id: chat_channel.id)
|
|
if existing_membership.present? && %w[active joining_request].exclude?(existing_membership.status)
|
|
status = existing_membership.update(status: "joining_request", role: "member")
|
|
else
|
|
membership = ChatChannelMembership.new(user_id: current_user.id, chat_channel_id: chat_channel.id,
|
|
role: "member", status: "joining_request")
|
|
status = membership.save
|
|
end
|
|
if status
|
|
render json: { status: "success", message: "Request Sent" }, status: :ok
|
|
else
|
|
render json: { status: 400, message: "Unable to join channel" }, status: :bad_request
|
|
end
|
|
end
|
|
|
|
def remove_membership
|
|
@chat_channel = ChatChannel.find(params[:chat_channel_id])
|
|
authorize @chat_channel, :update?
|
|
@chat_channel_membership = @chat_channel.chat_channel_memberships.find(params[:membership_id])
|
|
if params[:status] == "pending"
|
|
@chat_channel_membership.destroy
|
|
message = "Invitation removed."
|
|
else
|
|
membership = @chat_channel_membership
|
|
message = "@#{current_user.username} removed @#{membership.user.username} from #{membership.channel_name}"
|
|
send_chat_action_message(
|
|
message, current_user, @chat_channel_membership.chat_channel_id, "removed_from_channel"
|
|
)
|
|
@chat_channel_membership.update(status: "removed_from_channel")
|
|
message = "Removed #{@chat_channel_membership.user.name}"
|
|
end
|
|
|
|
render json: { status: "success", message: message, success: true }, status: :ok
|
|
end
|
|
|
|
def add_membership
|
|
@chat_channel = ChatChannel.find(params[:chat_channel_id])
|
|
authorize @chat_channel, :update?
|
|
@chat_channel_membership = @chat_channel.chat_channel_memberships.find(params[:membership_id])
|
|
|
|
return unless permitted_params[:user_action].present? && @chat_channel_membership.status == "joining_request"
|
|
|
|
respond_to_invitation(@chat_channel_membership.status)
|
|
end
|
|
|
|
def update
|
|
@chat_channel_membership = ChatChannelMembership.find(params[:id])
|
|
authorize @chat_channel_membership
|
|
respond_to_invitation(@chat_channel_membership.status)
|
|
end
|
|
|
|
def update_membership
|
|
@chat_channel_membership = ChatChannelMembership.find(params[:id])
|
|
authorize @chat_channel_membership
|
|
@chat_channel_membership.update(permitted_params)
|
|
if @chat_channel_membership.errors.any?
|
|
render json: { success: false, errors: @chat_channel_membership.errors.full_messages,
|
|
message: "Failed to update settings." }, status: :bad_request
|
|
else
|
|
render json: { success: true, message: "Personal settings updated." }, status: :ok
|
|
end
|
|
end
|
|
|
|
def leave_membership
|
|
chat_channel_membership = ChatChannelMembership.find_by(id: params[:id])
|
|
authorize chat_channel_membership
|
|
channel_name = chat_channel_membership.chat_channel.channel_name
|
|
send_chat_action_message("@#{current_user.username} left #{chat_channel_membership.channel_name}", current_user,
|
|
chat_channel_membership.chat_channel_id, "left_channel")
|
|
chat_channel_membership.update(status: "left_channel")
|
|
message = "You have left the channel #{channel_name}. It may take a moment to be removed from your list."
|
|
if chat_channel_membership.errors.any?
|
|
render json: { success: false, message: "Failed to update membership",
|
|
errors: chat_channel_membership.errors.full_messages }, status: :bad_request
|
|
else
|
|
render json: { success: true, message: message }, status: :ok
|
|
end
|
|
end
|
|
|
|
def request_details
|
|
user_chat_channels = ChatChannel.includes(:chat_channel_memberships).where(
|
|
chat_channel_memberships: { user_id: current_user.id, role: "mod", status: "active" },
|
|
)
|
|
@memberships = user_chat_channels.map(&:requested_memberships).flatten
|
|
@user_invitations = ChatChannelMembership.where(
|
|
user_id: current_user.id,
|
|
status: %w[pending],
|
|
).order("created_at DESC")
|
|
end
|
|
|
|
def update_membership_role
|
|
@chat_channel = ChatChannel.find_by(id: params[:id])
|
|
authorize @chat_channel, :update?
|
|
membership = ChatChannelMembership.find_by(
|
|
id: channel_membership_params[:membership_id],
|
|
chat_channel_id: @chat_channel.id,
|
|
)
|
|
|
|
membership.update(role: channel_membership_params[:role])
|
|
if membership.errors.any?
|
|
render json: {
|
|
success: false,
|
|
message: "Failed to update membership",
|
|
errors: chat_channel_membership.errors.full_messages
|
|
}, status: :bad_request
|
|
else
|
|
role = membership.reload.role
|
|
send_chat_action_message(
|
|
"@#{membership.user.username} role is updated as #{role}",
|
|
current_user, @chat_channel.id,
|
|
"updated"
|
|
)
|
|
|
|
render json: { success: true, message: "User Membership is updated" }, status: :ok
|
|
end
|
|
end
|
|
|
|
def join_channel_invitation
|
|
@chat_channel = ChatChannel.find_by(slug: params[:channel_slug])
|
|
authorize @chat_channel
|
|
invite_cache_key = "chat-channel-invite-#{@chat_channel.id}"
|
|
invitation_slug = Rails.cache.read(invite_cache_key)
|
|
existing_membership = ChatChannelMembership.find_by(user_id: current_user.id, chat_channel_id: @chat_channel.id)
|
|
redirect_to "/connect/#{@chat_channel.slug}" if existing_membership && existing_membership.status == "active"
|
|
@link_expired = true if invitation_slug != params[:invitation_slug]
|
|
end
|
|
|
|
def joining_invitation_response
|
|
chat_channel = ChatChannel.find_by(id: params[:chat_channel_id])
|
|
authorize chat_channel
|
|
if params[:user_action] == "accept"
|
|
membership = ChatChannelMembership.find_by(user_id: current_user.id, chat_channel_id: chat_channel.id)
|
|
if !membership
|
|
membership = ChatChannelMembership.create(user_id: current_user.id, chat_channel_id: chat_channel.id)
|
|
unless membership&.errors&.any?
|
|
send_chat_action_message("@#{membership.user.username} join the channel", current_user, chat_channel.id,
|
|
"joined")
|
|
end
|
|
elsif membership.status != "active"
|
|
# This check checks if the user already has the chatChannelMembership with the status pending, joining_request
|
|
# Then update it to as active.
|
|
membership.update(role: "member", status: "active")
|
|
send_chat_action_message("@#{membership.user.username} join the channel", current_user,
|
|
membership.chat_channel_id, "joined")
|
|
end
|
|
|
|
if membership&.errors&.any?
|
|
flash[:settings_notice] = membership.errors.full_messages
|
|
redirect_to root_path
|
|
end
|
|
|
|
redirect_to connect_path(chat_channel.slug)
|
|
else
|
|
redirect_to root_path
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def permitted_params
|
|
params.require(:chat_channel_membership).permit(:user_action, :show_global_badge_notification)
|
|
end
|
|
|
|
def channel_membership_params
|
|
params.require(:chat_channel_membership).permit(:chat_channel_id, :invitation_usernames, :membership_id, :role)
|
|
end
|
|
|
|
def respond_to_invitation(previous_status)
|
|
if permitted_params[:user_action] == "accept"
|
|
@chat_channel_membership.update(status: "active")
|
|
channel_name = @chat_channel_membership.chat_channel.channel_name
|
|
|
|
if previous_status == "pending"
|
|
send_chat_action_message(
|
|
"@#{current_user.username} joined #{@chat_channel_membership.channel_name}",
|
|
current_user,
|
|
@chat_channel_membership.chat_channel_id,
|
|
"joined",
|
|
)
|
|
|
|
notice = "Invitation to #{channel_name} accepted. It may take a moment to show up in your list."
|
|
else
|
|
send_chat_action_message(
|
|
"@#{current_user.username} added @#{@chat_channel_membership.user.username}",
|
|
current_user,
|
|
@chat_channel_membership.chat_channel_id,
|
|
"joined",
|
|
)
|
|
|
|
NotifyMailer
|
|
.with(membership: @chat_channel_membership, inviter: @chat_channel_membership.user)
|
|
.channel_invite_email
|
|
.deliver_later
|
|
|
|
notice = "Accepted request of #{@chat_channel_membership.user.username} to join #{channel_name}."
|
|
end
|
|
else
|
|
@chat_channel_membership.update(status: "rejected")
|
|
notice = "Invitation rejected."
|
|
end
|
|
|
|
membership_user = helpers.format_membership(@chat_channel_membership)
|
|
flash[:settings_notice] = notice
|
|
|
|
respond_to do |format|
|
|
format.html { redirect_to chat_channel_memberships_path }
|
|
format.json do
|
|
render json: {
|
|
status: "success",
|
|
message: flash[:settings_notice],
|
|
success: true,
|
|
membership: membership_user
|
|
}, status: :ok
|
|
end
|
|
end
|
|
end
|
|
|
|
def send_chat_action_message(message, user, channel_id, action)
|
|
temp_message_id = (0...20).map { ("a".."z").to_a[rand(8)] }.join
|
|
message = Message.create("message_markdown" => message, "user_id" => user.id, "chat_channel_id" => channel_id,
|
|
"chat_action" => action)
|
|
pusher_message_created(false, message, temp_message_id) unless message.left_channel?
|
|
end
|
|
|
|
def user_not_authorized
|
|
render json: { success: false, message: "User not authorized" }, status: :unauthorized
|
|
end
|
|
|
|
def record_not_found
|
|
render json: { success: false, message: "not found" }, status: :not_found
|
|
end
|
|
end
|