fix: support HTTPS proxy by using relative API paths
All checks were successful
CI / skip-ci-check (pull_request) Successful in 1m51s
CI / lint-and-type-check (pull_request) Successful in 2m32s
CI / python-lint (pull_request) Successful in 2m16s
CI / test-backend (pull_request) Successful in 4m11s
CI / build (pull_request) Successful in 4m59s
CI / secret-scanning (pull_request) Successful in 1m59s
CI / dependency-scan (pull_request) Successful in 1m58s
CI / sast-scan (pull_request) Successful in 3m7s
CI / workflow-summary (pull_request) Successful in 1m50s
All checks were successful
CI / skip-ci-check (pull_request) Successful in 1m51s
CI / lint-and-type-check (pull_request) Successful in 2m32s
CI / python-lint (pull_request) Successful in 2m16s
CI / test-backend (pull_request) Successful in 4m11s
CI / build (pull_request) Successful in 4m59s
CI / secret-scanning (pull_request) Successful in 1m59s
CI / dependency-scan (pull_request) Successful in 1m58s
CI / sast-scan (pull_request) Successful in 3m7s
CI / workflow-summary (pull_request) Successful in 1m50s
- Update API client to use relative paths when VITE_API_URL is empty - Fix EventSource URLs to use window.location.origin for proxy compatibility - Update image/video URL construction to use relative paths - Add debug logging for API response troubleshooting - All API calls now work correctly when served through HTTPS proxy This fixes mixed content errors and allows the admin frontend to work when accessed via HTTPS domain with reverse proxy (Caddy/nginx).
This commit is contained in:
parent
49ae9728f3
commit
70cfd63ca1
@ -48,8 +48,12 @@ export const authApi = {
|
||||
},
|
||||
|
||||
me: async (): Promise<UserResponse> => {
|
||||
const { data } = await apiClient.get<UserResponse>('/api/v1/auth/me')
|
||||
return data
|
||||
const response = await apiClient.get<UserResponse>('/api/v1/auth/me')
|
||||
console.log('🔍 Raw /me API response:', response)
|
||||
console.log('🔍 Response data:', response.data)
|
||||
console.log('🔍 Response data type:', typeof response.data)
|
||||
console.log('🔍 Response data keys:', response.data ? Object.keys(response.data) : 'no keys')
|
||||
return response.data
|
||||
},
|
||||
|
||||
changePassword: async (
|
||||
|
||||
@ -3,7 +3,11 @@ import axios from 'axios'
|
||||
// Get API base URL from environment variable or use default
|
||||
// The .env file should contain: VITE_API_URL=http://127.0.0.1:8000
|
||||
// Alternatively, Vite proxy can be used (configured in vite.config.ts) by setting VITE_API_URL to empty string
|
||||
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://127.0.0.1:8000'
|
||||
// When VITE_API_URL is empty/undefined, use relative path to work with HTTPS proxy
|
||||
const envApiUrl = import.meta.env.VITE_API_URL
|
||||
const API_BASE_URL = envApiUrl && envApiUrl.trim() !== ''
|
||||
? envApiUrl
|
||||
: '' // Use relative path when empty - works with proxy and HTTPS
|
||||
|
||||
export const apiClient = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
|
||||
@ -27,8 +27,11 @@ export const jobsApi = {
|
||||
},
|
||||
|
||||
streamJobProgress: (jobId: string): EventSource => {
|
||||
// EventSource needs absolute URL - use VITE_API_URL or fallback to direct backend URL
|
||||
const baseURL = import.meta.env.VITE_API_URL || 'http://127.0.0.1:8000'
|
||||
// EventSource needs absolute URL - use VITE_API_URL or construct from current origin
|
||||
const envApiUrl = import.meta.env.VITE_API_URL
|
||||
const baseURL = envApiUrl && envApiUrl.trim() !== ''
|
||||
? envApiUrl
|
||||
: window.location.origin // Use current origin when empty - works with proxy and HTTPS
|
||||
return new EventSource(`${baseURL}/api/v1/jobs/stream/${jobId}`)
|
||||
},
|
||||
|
||||
|
||||
@ -70,8 +70,11 @@ export const photosApi = {
|
||||
},
|
||||
|
||||
streamJobProgress: (jobId: string): EventSource => {
|
||||
// EventSource needs absolute URL - use VITE_API_URL or fallback to direct backend URL
|
||||
const baseURL = import.meta.env.VITE_API_URL || 'http://127.0.0.1:8000'
|
||||
// EventSource needs absolute URL - use VITE_API_URL or construct from current origin
|
||||
const envApiUrl = import.meta.env.VITE_API_URL
|
||||
const baseURL = envApiUrl && envApiUrl.trim() !== ''
|
||||
? envApiUrl
|
||||
: window.location.origin // Use current origin when empty - works with proxy and HTTPS
|
||||
return new EventSource(`${baseURL}/api/v1/jobs/stream/${jobId}`)
|
||||
},
|
||||
|
||||
|
||||
@ -108,12 +108,18 @@ export const videosApi = {
|
||||
},
|
||||
|
||||
getThumbnailUrl: (videoId: number): string => {
|
||||
const baseURL = import.meta.env.VITE_API_URL || 'http://127.0.0.1:8000'
|
||||
const envApiUrl = import.meta.env.VITE_API_URL
|
||||
const baseURL = envApiUrl && envApiUrl.trim() !== ''
|
||||
? envApiUrl
|
||||
: '' // Use relative path when empty - works with proxy and HTTPS
|
||||
return `${baseURL}/api/v1/videos/${videoId}/thumbnail`
|
||||
},
|
||||
|
||||
getVideoUrl: (videoId: number): string => {
|
||||
const baseURL = import.meta.env.VITE_API_URL || 'http://127.0.0.1:8000'
|
||||
const envApiUrl = import.meta.env.VITE_API_URL
|
||||
const baseURL = envApiUrl && envApiUrl.trim() !== ''
|
||||
? envApiUrl
|
||||
: '' // Use relative path when empty - works with proxy and HTTPS
|
||||
return `${baseURL}/api/v1/videos/${videoId}/video`
|
||||
},
|
||||
}
|
||||
|
||||
@ -38,6 +38,12 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
authApi
|
||||
.me()
|
||||
.then((user) => {
|
||||
console.log('🔍 Auth /me response:', {
|
||||
username: user.username,
|
||||
is_admin: user.is_admin,
|
||||
role: user.role,
|
||||
permissions: user.permissions
|
||||
})
|
||||
setAuthState({
|
||||
isAuthenticated: true,
|
||||
username: user.username,
|
||||
@ -81,6 +87,12 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
localStorage.setItem('access_token', tokens.access_token)
|
||||
localStorage.setItem('refresh_token', tokens.refresh_token)
|
||||
const user = await authApi.me()
|
||||
console.log('🔍 Login /me response:', {
|
||||
username: user.username,
|
||||
is_admin: user.is_admin,
|
||||
role: user.role,
|
||||
permissions: user.permissions
|
||||
})
|
||||
const passwordChangeRequired = tokens.password_change_required || false
|
||||
setAuthState({
|
||||
isAuthenticated: true,
|
||||
@ -133,7 +145,13 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
if (authState.isAdmin) {
|
||||
return true
|
||||
}
|
||||
return Boolean(authState.permissions[featureKey])
|
||||
const hasPerm = Boolean(authState.permissions[featureKey])
|
||||
console.log(`🔍 hasPermission(${featureKey}):`, {
|
||||
isAdmin: authState.isAdmin,
|
||||
hasPerm,
|
||||
permissions: authState.permissions
|
||||
})
|
||||
return hasPerm
|
||||
},
|
||||
[authState.isAdmin, authState.permissions]
|
||||
)
|
||||
|
||||
@ -604,7 +604,8 @@ export default function Identify() {
|
||||
|
||||
const preloadImages = () => {
|
||||
const preloadUrls: string[] = []
|
||||
const baseUrl = apiClient.defaults.baseURL || 'http://127.0.0.1:8000'
|
||||
// Use relative path when baseURL is empty (works with proxy and HTTPS)
|
||||
const baseUrl = apiClient.defaults.baseURL || ''
|
||||
|
||||
// Preload next face
|
||||
if (currentIdx + 1 < faces.length) {
|
||||
|
||||
@ -41,7 +41,8 @@ export default function ReportedPhotos() {
|
||||
|
||||
// Create direct backend URLs for images (only for non-video photos)
|
||||
const newImageUrls: Record<number, string> = {}
|
||||
const baseURL = apiClient.defaults.baseURL || 'http://10.0.10.121:8000'
|
||||
// Use relative path when baseURL is empty (works with proxy and HTTPS)
|
||||
const baseURL = apiClient.defaults.baseURL || ''
|
||||
response.items.forEach((reported) => {
|
||||
if (reported.photo_id && reported.photo_media_type !== 'video') {
|
||||
// Use direct backend URL - the backend endpoint doesn't require auth for images
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user