DEV: Cleanup caption endpoint and account for secure uploads (#478)
Utilizes the check for secure upload permissions from core PR https://github.com/discourse/discourse/pull/25758 and cleans up controller codes and spec code to reuse existing code and better reflect reality.
This commit is contained in:
parent
cf19ce0d72
commit
0c1aad7850
|
@ -8,6 +8,8 @@ module DiscourseAi
|
||||||
before_action :ensure_can_request_suggestions
|
before_action :ensure_can_request_suggestions
|
||||||
before_action :rate_limiter_performed!, except: %i[prompts]
|
before_action :rate_limiter_performed!, except: %i[prompts]
|
||||||
|
|
||||||
|
include SecureUploadEndpointHelpers
|
||||||
|
|
||||||
def suggest
|
def suggest
|
||||||
input = get_text_param!
|
input = get_text_param!
|
||||||
|
|
||||||
|
@ -109,16 +111,16 @@ module DiscourseAi
|
||||||
image_url = params[:image_url]
|
image_url = params[:image_url]
|
||||||
raise Discourse::InvalidParameters.new(:image_url) if !image_url
|
raise Discourse::InvalidParameters.new(:image_url) if !image_url
|
||||||
|
|
||||||
image = Upload.find_by(sha1: Upload.sha1_from_long_url(image_url))
|
image = upload_from_full_url(image_url)
|
||||||
|
raise Discourse::NotFound if image.blank?
|
||||||
if image&.secure?
|
final_image_url = get_caption_url(image, image_url)
|
||||||
url = Upload.signed_url_from_secure_uploads_url(image_url)
|
|
||||||
else
|
|
||||||
url = UrlHelper.absolute(image_url)
|
|
||||||
end
|
|
||||||
|
|
||||||
hijack do
|
hijack do
|
||||||
caption = DiscourseAi::AiHelper::Assistant.new.generate_image_caption(url, current_user)
|
caption =
|
||||||
|
DiscourseAi::AiHelper::Assistant.new.generate_image_caption(
|
||||||
|
final_image_url,
|
||||||
|
current_user,
|
||||||
|
)
|
||||||
render json: { caption: caption }, status: 200
|
render json: { caption: caption }, status: 200
|
||||||
end
|
end
|
||||||
rescue DiscourseAi::Completions::Endpoints::Base::CompletionFailed, Net::HTTPBadResponse
|
rescue DiscourseAi::Completions::Endpoints::Base::CompletionFailed, Net::HTTPBadResponse
|
||||||
|
@ -141,14 +143,18 @@ module DiscourseAi
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_can_request_suggestions
|
def ensure_can_request_suggestions
|
||||||
user_group_ids = current_user.group_ids
|
if !current_user.in_any_groups?(SiteSetting.ai_helper_allowed_groups_map)
|
||||||
|
raise Discourse::InvalidAccess
|
||||||
allowed =
|
end
|
||||||
SiteSetting.ai_helper_allowed_groups_map.any? do |group_id|
|
|
||||||
user_group_ids.include?(group_id)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
raise Discourse::InvalidAccess if !allowed
|
def get_caption_url(image_upload, image_url)
|
||||||
|
if image_upload.secure?
|
||||||
|
check_secure_upload_permission(image_upload)
|
||||||
|
return Discourse.store.url_for(image_upload)
|
||||||
|
end
|
||||||
|
|
||||||
|
UrlHelper.absolute(image_url)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -109,15 +109,15 @@ RSpec.describe DiscourseAi::AiHelper::AssistantController do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#caption_image" do
|
describe "#caption_image" do
|
||||||
let(:image_url) { "https://example.com/image.jpg" }
|
fab!(:upload) { Fabricate(:upload) }
|
||||||
|
let(:image_url) { "#{Discourse.base_url}#{upload.url}" }
|
||||||
let(:caption) { "A picture of a cat sitting on a table" }
|
let(:caption) { "A picture of a cat sitting on a table" }
|
||||||
|
|
||||||
context "when logged in as an allowed user" do
|
context "when logged in as an allowed user" do
|
||||||
fab!(:user)
|
fab!(:user) { Fabricate(:user, refresh_auto_groups: true) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
user.group_ids = [Group::AUTO_GROUPS[:trust_level_1]]
|
|
||||||
SiteSetting.ai_helper_allowed_groups = Group::AUTO_GROUPS[:trust_level_1]
|
SiteSetting.ai_helper_allowed_groups = Group::AUTO_GROUPS[:trust_level_1]
|
||||||
SiteSetting.ai_llava_endpoint = "https://example.com"
|
SiteSetting.ai_llava_endpoint = "https://example.com"
|
||||||
|
|
||||||
|
@ -147,6 +147,50 @@ RSpec.describe DiscourseAi::AiHelper::AssistantController do
|
||||||
|
|
||||||
expect(response.status).to eq(400)
|
expect(response.status).to eq(400)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns a 404 error if no upload is found" do
|
||||||
|
post "/discourse-ai/ai-helper/caption_image",
|
||||||
|
params: {
|
||||||
|
image_url: "http://blah.com/img.jpeg",
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "for secure uploads" do
|
||||||
|
fab!(:group) { Fabricate(:group) }
|
||||||
|
fab!(:private_category) { Fabricate(:private_category, group: group) }
|
||||||
|
fab!(:post_in_secure_context) do
|
||||||
|
Fabricate(:post, topic: Fabricate(:topic, category: private_category))
|
||||||
|
end
|
||||||
|
fab!(:upload) { Fabricate(:secure_upload, access_control_post: post_in_secure_context) }
|
||||||
|
let(:image_url) { "#{Discourse.base_url}/secure-uploads/#{upload.url}" }
|
||||||
|
|
||||||
|
before { enable_secure_uploads }
|
||||||
|
|
||||||
|
it "returns a 403 error if the user cannot access the secure upload" do
|
||||||
|
post "/discourse-ai/ai-helper/caption_image", params: { image_url: image_url }
|
||||||
|
expect(response.status).to eq(403)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a 200 message and caption if user can access the secure upload" do
|
||||||
|
group.add(user)
|
||||||
|
post "/discourse-ai/ai-helper/caption_image", params: { image_url: image_url }
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(response.parsed_body["caption"]).to eq(caption)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "if the input URL is for a secure upload but not on the secure-uploads path" do
|
||||||
|
let(:image_url) { "#{Discourse.base_url}#{upload.url}" }
|
||||||
|
|
||||||
|
it "creates a signed URL properly and makes the caption" do
|
||||||
|
group.add(user)
|
||||||
|
post "/discourse-ai/ai-helper/caption_image", params: { image_url: image_url }
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(response.parsed_body["caption"]).to eq(caption)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue