mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-08-12 10:00:42 +09:00
3ca1dcbf77
Bots can only create. A lifecycle notification — an alert that fires and then resolves, a deploy that starts and finishes, a backup that runs — therefore has to post a second message, and the room becomes an append-only log of states rather than a view of the current one. Adds PATCH and DELETE inside the existing bot_key scope, routed to Messages::ByBotsController. The body is read the way create reads it, so updating a message is the same request shape as posting one. No new authorization: both actions already run through ensure_can_administer, and can_administer? grants access only to a record the user created, so a bot key reaches that bot's own messages and no others. set_room narrows it again by looking the room up through the bot's own memberships. A leaked bot key gains what it could already do by posting: write to rooms that bot belongs to. update answers head :ok rather than the redirect, which meant extracting the update and its broadcast into update_message — calling super and then head would double render, since the parent redirects inside the action. destroy needs no split, because the parent renders implicitly like create does.
72 lines
1.8 KiB
Ruby
72 lines
1.8 KiB
Ruby
class Messages::ByBotsController < MessagesController
|
|
include RawRequestBody
|
|
|
|
allow_bot_access only: %i[ index create update destroy ]
|
|
|
|
before_action :set_room
|
|
before_action :set_message, only: %i[ update destroy ]
|
|
before_action :ensure_can_administer, only: %i[ update destroy ]
|
|
before_action :ensure_body_or_attachment_present, only: :create
|
|
|
|
def index
|
|
@messages = find_paged_messages
|
|
set_pagination_headers
|
|
end
|
|
|
|
def create
|
|
super
|
|
head :created, location: message_url(@message)
|
|
end
|
|
|
|
# ensure_can_administer still applies, and can_administer? only grants access to
|
|
# a record the user created, so a bot key reaches that bot's own messages and no others.
|
|
def update
|
|
update_message
|
|
head :ok
|
|
end
|
|
|
|
def destroy
|
|
super
|
|
head :no_content
|
|
end
|
|
|
|
private
|
|
def set_room
|
|
@room = Current.user.rooms.find_by(id: params[:room_id])
|
|
|
|
head :not_found unless @room
|
|
end
|
|
|
|
def ensure_body_or_attachment_present
|
|
if params[:attachment].blank? && raw_request_body.blank?
|
|
head :unprocessable_content
|
|
end
|
|
end
|
|
|
|
def set_pagination_headers
|
|
headers["X-Total-Count"] = @room.messages.count.to_s
|
|
|
|
if next_page = next_page_params
|
|
headers["Link"] = %(<#{room_bot_messages_url(@room, params[:bot_key], **next_page)}>; rel="next")
|
|
end
|
|
end
|
|
|
|
def next_page_params
|
|
if @messages.any?
|
|
if params[:after].present?
|
|
{ after: @messages.last.id } if @room.messages.after(@messages.last).exists?
|
|
else
|
|
{ before: @messages.first.id } if @room.messages.before(@messages.first).exists?
|
|
end
|
|
end
|
|
end
|
|
|
|
def message_params
|
|
if params[:attachment]
|
|
params.permit(:attachment)
|
|
else
|
|
{ body: raw_request_body }
|
|
end
|
|
end
|
|
end
|