Merge pull request 'fix: support HTTPS proxy by using relative API paths' (#8) from fix/https-proxy-api-routing into dev
All checks were successful
CI / skip-ci-check (pull_request) Successful in 1m52s
CI / lint-and-type-check (pull_request) Successful in 2m31s
CI / python-lint (pull_request) Successful in 2m19s
CI / test-backend (pull_request) Successful in 4m7s
CI / build (pull_request) Successful in 4m58s
CI / secret-scanning (pull_request) Successful in 2m0s
CI / dependency-scan (pull_request) Successful in 2m0s
CI / sast-scan (pull_request) Successful in 3m6s
CI / workflow-summary (pull_request) Successful in 1m50s

Reviewed-on: #8
This commit is contained in:
tanyar09 2026-01-23 14:04:32 -05:00
commit 5b8e22d9d1
8 changed files with 52 additions and 12 deletions

View File

@ -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 (

View File

@ -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,

View File

@ -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}`)
},

View File

@ -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}`)
},

View File

@ -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`
},
}

View File

@ -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]
)

View File

@ -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) {

View File

@ -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