Fix API controllers to use correct database column names
- Fix model_pricing table references (model_id -> model, display_name -> model)
- Fix price columns (output_price_per_1k -> output_price_per_million)
- Add price conversion (per_million / 1000 = per_1k) in all API responses
- Add whereNotNull('model') filters to exclude invalid entries
- Add getModelDisplayName() helper method to all controllers
- Fix AccountController to use gateway_users budget fields directly
- Remove Budget model dependencies from AccountController
- Add custom Scramble server URL configuration for API docs
- Create ScrambleServiceProvider to set correct /api prefix
- Add migration to rename user_id to gateway_user_id in llm_requests
- Add custom ApiGuard for gateway_users authentication
- Update all API controllers: AccountController, ModelController, PricingController, ProviderController
All API endpoints now working correctly:
- GET /api/account
- GET /api/models
- GET /api/pricing
- GET /api/providers/{provider}
This commit is contained in:
@@ -164,7 +164,7 @@
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="text-lg font-semibold text-gray-900">API Keys</h2>
|
||||
{{-- TODO: Enable when API Keys Management is implemented --}}
|
||||
{{-- <a href="{{ route('api-keys.create', ['user_id' => $user->user_id]) }}"
|
||||
{{-- <a href="{{ route('keys.create', ['user_id' => $user->user_id]) }}"
|
||||
class="text-sm text-indigo-600 hover:text-indigo-900">
|
||||
+ Create Key
|
||||
</a> --}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
{{ __('Create New API Key') }}
|
||||
</h2>
|
||||
<a href="{{ route('api-keys.index') }}"
|
||||
<a href="{{ route('keys.index') }}"
|
||||
class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
|
||||
@@ -64,7 +64,7 @@
|
||||
<!-- Create Form -->
|
||||
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-6 text-gray-900">
|
||||
<form method="POST" action="{{ route('api-keys.store') }}" class="space-y-6">
|
||||
<form method="POST" action="{{ route('keys.store') }}" class="space-y-6">
|
||||
@csrf
|
||||
|
||||
<!-- Key Name -->
|
||||
@@ -167,7 +167,7 @@
|
||||
|
||||
<!-- Submit Buttons -->
|
||||
<div class="flex items-center justify-end space-x-4 pt-4">
|
||||
<a href="{{ route('api-keys.index') }}"
|
||||
<a href="{{ route('keys.index') }}"
|
||||
class="inline-flex justify-center py-2 px-4 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
||||
Cancel
|
||||
</a>
|
||||
@@ -4,7 +4,7 @@
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
{{ __('API Keys Management') }}
|
||||
</h2>
|
||||
<a href="{{ route('api-keys.create') }}"
|
||||
<a href="{{ route('keys.create') }}"
|
||||
class="inline-flex items-center px-4 py-2 bg-blue-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-blue-700 focus:bg-blue-700 active:bg-blue-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition ease-in-out duration-150">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
|
||||
@@ -44,7 +44,7 @@
|
||||
<p>This is the only time you'll see this key. Copy it now:</p>
|
||||
<div class="mt-2 flex items-center">
|
||||
<code id="new-api-key" class="bg-white px-4 py-2 rounded border border-yellow-300 font-mono text-sm">{{ session('new_api_key') }}</code>
|
||||
<button onclick="copyToClipboard('new-api-key')"
|
||||
<button onclick="copyToClipboard('new-api-key', event)"
|
||||
class="ml-2 px-3 py-2 bg-yellow-500 text-white rounded hover:bg-yellow-600">
|
||||
Copy
|
||||
</button>
|
||||
@@ -58,7 +58,7 @@
|
||||
<!-- Filters -->
|
||||
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg mb-6">
|
||||
<div class="p-6">
|
||||
<form method="GET" action="{{ route('api-keys.index') }}" class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<form method="GET" action="{{ route('keys.index') }}" class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<!-- Search -->
|
||||
<div>
|
||||
<label for="search" class="block text-sm font-medium text-gray-700 mb-1">Search</label>
|
||||
@@ -183,10 +183,10 @@
|
||||
{{ $key->created_at->format('Y-m-d H:i') }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<a href="{{ route('api-keys.show', $key->token) }}"
|
||||
<a href="{{ route('keys.show', $key->token) }}"
|
||||
class="text-blue-600 hover:text-blue-900 mr-3">View</a>
|
||||
@if($key->is_active && !$key->is_expired)
|
||||
<form action="{{ route('api-keys.revoke', $key->token) }}"
|
||||
<form action="{{ route('keys.revoke', $key->token) }}"
|
||||
method="POST"
|
||||
class="inline"
|
||||
onsubmit="return confirm('Are you sure you want to revoke this API key? This action cannot be undone.');">
|
||||
@@ -215,7 +215,7 @@
|
||||
<h3 class="mt-2 text-sm font-medium text-gray-900">No API keys found</h3>
|
||||
<p class="mt-1 text-sm text-gray-500">Get started by creating a new API key.</p>
|
||||
<div class="mt-6">
|
||||
<a href="{{ route('api-keys.create') }}"
|
||||
<a href="{{ route('keys.create') }}"
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
||||
<svg class="-ml-1 mr-2 h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
|
||||
@@ -232,7 +232,7 @@
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
function copyToClipboard(elementId) {
|
||||
function copyToClipboard(elementId, event) {
|
||||
const element = document.getElementById(elementId);
|
||||
const text = element.textContent;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
{{ __('API Key Details') }}
|
||||
</h2>
|
||||
<a href="{{ route('api-keys.index') }}"
|
||||
<a href="{{ route('keys.index') }}"
|
||||
class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
|
||||
@@ -103,7 +103,7 @@
|
||||
<!-- Action Buttons -->
|
||||
@if($apiKey->is_active && !$apiKey->is_expired)
|
||||
<div class="mt-6 pt-6 border-t border-gray-200">
|
||||
<form action="{{ route('api-keys.revoke', $apiKey->id) }}"
|
||||
<form action="{{ route('keys.revoke', $apiKey->id) }}"
|
||||
method="POST"
|
||||
onsubmit="return confirm('Are you sure you want to revoke this API key? This action cannot be undone and all requests using this key will be rejected immediately.');">
|
||||
@csrf
|
||||
@@ -36,7 +36,7 @@ new class extends Component
|
||||
<x-nav-link :href="route('gateway-users.index')" :active="request()->routeIs('gateway-users.*')" wire:navigate>
|
||||
{{ __('Gateway Users') }}
|
||||
</x-nav-link>
|
||||
<x-nav-link :href="route('api-keys.index')" :active="request()->routeIs('api-keys.*')" wire:navigate>
|
||||
<x-nav-link :href="route('keys.index')" :active="request()->routeIs('keys.*')" wire:navigate>
|
||||
{{ __('API Keys') }}
|
||||
</x-nav-link>
|
||||
<x-nav-link :href="route('budgets.index')" :active="request()->routeIs('budgets.*')" wire:navigate>
|
||||
@@ -108,7 +108,7 @@ new class extends Component
|
||||
<x-responsive-nav-link :href="route('gateway-users.index')" :active="request()->routeIs('gateway-users.*')" wire:navigate>
|
||||
{{ __('Gateway Users') }}
|
||||
</x-responsive-nav-link>
|
||||
<x-responsive-nav-link :href="route('api-keys.index')" :active="request()->routeIs('api-keys.*')" wire:navigate>
|
||||
<x-responsive-nav-link :href="route('keys.index')" :active="request()->routeIs('keys.*')" wire:navigate>
|
||||
{{ __('API Keys') }}
|
||||
</x-responsive-nav-link>
|
||||
<x-responsive-nav-link :href="route('budgets.index')" :active="request()->routeIs('budgets.*')" wire:navigate>
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
modelHint.textContent = 'Loading models from ' + provider + '...';
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/provider-models/${provider}`);
|
||||
const response = await fetch(`/admin/provider-models/${provider}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success && data.models) {
|
||||
|
||||
Reference in New Issue
Block a user