2025-06-18 04:32:14 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require "test_helper"
|
|
|
|
|
|
|
|
class Api::V1::ChatsControllerTest < ActionDispatch::IntegrationTest
|
|
|
|
setup do
|
|
|
|
@user = users(:family_admin)
|
|
|
|
@user.update!(ai_enabled: true)
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
@oauth_app = Doorkeeper::Application.create!(
|
|
|
|
name: "Test API App",
|
|
|
|
redirect_uri: "https://example.com/callback",
|
|
|
|
scopes: "read write read_write"
|
|
|
|
)
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
@read_token = Doorkeeper::AccessToken.create!(
|
|
|
|
application: @oauth_app,
|
|
|
|
resource_owner_id: @user.id,
|
|
|
|
scopes: "read"
|
|
|
|
)
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
@write_token = Doorkeeper::AccessToken.create!(
|
|
|
|
application: @oauth_app,
|
|
|
|
resource_owner_id: @user.id,
|
|
|
|
scopes: "read_write"
|
|
|
|
)
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
@chat = chats(:one)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "should require authentication" do
|
|
|
|
get "/api/v1/chats"
|
|
|
|
assert_response :unauthorized
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
test "should require AI to be enabled" do
|
|
|
|
@user.update!(ai_enabled: false)
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
get "/api/v1/chats", headers: bearer_auth_header(@read_token)
|
|
|
|
assert_response :forbidden
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
response_body = JSON.parse(response.body)
|
|
|
|
assert_equal "feature_disabled", response_body["error"]
|
|
|
|
end
|
|
|
|
|
|
|
|
test "should list chats with read scope" do
|
|
|
|
get "/api/v1/chats", headers: bearer_auth_header(@read_token)
|
|
|
|
assert_response :success
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
response_body = JSON.parse(response.body)
|
|
|
|
assert response_body["chats"].is_a?(Array)
|
|
|
|
assert response_body["pagination"].present?
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
test "should show chat with messages" do
|
|
|
|
get "/api/v1/chats/#{@chat.id}", headers: bearer_auth_header(@read_token)
|
|
|
|
assert_response :success
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
response_body = JSON.parse(response.body)
|
|
|
|
assert_equal @chat.id, response_body["id"]
|
|
|
|
assert response_body["messages"].is_a?(Array)
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
test "should create chat with write scope" do
|
|
|
|
assert_difference "Chat.count" do
|
2025-06-18 04:36:31 -05:00
|
|
|
post "/api/v1/chats",
|
2025-06-18 04:32:14 -05:00
|
|
|
params: { title: "New chat", message: "Hello AI" },
|
|
|
|
headers: bearer_auth_header(@write_token)
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
assert_response :created
|
|
|
|
response_body = JSON.parse(response.body)
|
|
|
|
assert_equal "New chat", response_body["title"]
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
test "should not create chat with read scope" do
|
2025-06-18 04:36:31 -05:00
|
|
|
post "/api/v1/chats",
|
2025-06-18 04:32:14 -05:00
|
|
|
params: { title: "New chat" },
|
|
|
|
headers: bearer_auth_header(@read_token)
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
assert_response :forbidden
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
test "should update chat" do
|
|
|
|
patch "/api/v1/chats/#{@chat.id}",
|
|
|
|
params: { title: "Updated title" },
|
|
|
|
headers: bearer_auth_header(@write_token)
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
assert_response :success
|
|
|
|
response_body = JSON.parse(response.body)
|
|
|
|
assert_equal "Updated title", response_body["title"]
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
test "should delete chat" do
|
|
|
|
assert_difference "Chat.count", -1 do
|
|
|
|
delete "/api/v1/chats/#{@chat.id}", headers: bearer_auth_header(@write_token)
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
assert_response :no_content
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
test "should not access other user's chat" do
|
|
|
|
other_user = users(:family_member)
|
|
|
|
other_user.update!(family: families(:empty))
|
|
|
|
other_chat = chats(:two)
|
|
|
|
other_chat.update!(user: other_user)
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
get "/api/v1/chats/#{other_chat.id}", headers: bearer_auth_header(@read_token)
|
|
|
|
assert_response :not_found
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
test "should support API key authentication" do
|
|
|
|
# Remove any existing API keys for this user
|
|
|
|
@user.api_keys.destroy_all
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
plain_key = ApiKey.generate_secure_key
|
|
|
|
api_key = @user.api_keys.build(
|
|
|
|
name: "Test API Key",
|
2025-06-18 04:36:31 -05:00
|
|
|
scopes: [ "read_write" ]
|
2025-06-18 04:32:14 -05:00
|
|
|
)
|
|
|
|
api_key.key = plain_key
|
|
|
|
api_key.save!
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
get "/api/v1/chats", headers: { "X-Api-Key" => plain_key }
|
|
|
|
assert_response :success
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
private
|
2025-06-18 04:36:31 -05:00
|
|
|
|
2025-06-18 04:32:14 -05:00
|
|
|
def bearer_auth_header(token)
|
|
|
|
{ "Authorization" => "Bearer #{token.token}" }
|
|
|
|
end
|
2025-06-18 04:36:31 -05:00
|
|
|
end
|