Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
A
aisbf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexlab
aisbf
Commits
5bf3e58c
Commit
5bf3e58c
authored
May 12, 2026
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: normalize dashboard proxy-aware client urls
parent
ece6dbaa
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
257 additions
and
12 deletions
+257
-12
autoselect.html
templates/dashboard/autoselect.html
+1
-1
market.html
templates/dashboard/market.html
+5
-4
providers.html
templates/dashboard/providers.html
+3
-1
rotations.html
templates/dashboard/rotations.html
+2
-2
user_autoselects.html
templates/dashboard/user_autoselects.html
+1
-1
user_providers.html
templates/dashboard/user_providers.html
+1
-1
user_rotations.html
templates/dashboard/user_rotations.html
+2
-2
test_dashboard_proxy_awareness.py
tests/routes/test_dashboard_proxy_awareness.py
+242
-0
No files found.
templates/dashboard/autoselect.html
View file @
5bf3e58c
...
@@ -199,7 +199,7 @@ async function msOpenAll(inputId, cb) {
...
@@ -199,7 +199,7 @@ async function msOpenAll(inputId, cb) {
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'autoselect.no_models_loaded'
);
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'autoselect.no_models_loaded'
);
document
.
getElementById
(
'ms-results'
).
innerHTML
=
`<p style="color:var(--color-muted);text-align:center;padding:20px;">
${
window
.
i18n
.
t
(
'autoselect.loading'
)}
</p>`
;
document
.
getElementById
(
'ms-results'
).
innerHTML
=
`<p style="color:var(--color-muted);text-align:center;padding:20px;">
${
window
.
i18n
.
t
(
'autoselect.loading'
)}
</p>`
;
try
{
try
{
const
r
=
await
fetch
(
'/dashboard/search-all-models?refresh=true'
);
const
r
=
await
fetch
(
`
${
BASE_PATH
}
/dashboard/search-all-models?refresh=true`
);
if
(
_msCancelled
)
return
;
if
(
_msCancelled
)
return
;
const
data
=
await
r
.
json
();
const
fetched
=
data
.
models
||
[];
const
data
=
await
r
.
json
();
const
fetched
=
data
.
models
||
[];
_msAllItems
=
fetched
;
_msAllItems
=
fetched
;
...
...
templates/dashboard/market.html
View file @
5bf3e58c
...
@@ -56,6 +56,7 @@
...
@@ -56,6 +56,7 @@
{% block extra_js %}
{% block extra_js %}
<script>
<script>
const
BASE_PATH
=
{{
(
request
.
scope
.
get
(
'root_path'
,
''
)
or
''
)
|
tojson
}};
const
listings
=
{{
market_listings_json
|
safe
}};
const
listings
=
{{
market_listings_json
|
safe
}};
const
currencySymbol
=
{{
currency_symbol
|
tojson
}};
const
currencySymbol
=
{{
currency_symbol
|
tojson
}};
const
marketSettings
=
{{
market_settings_json
|
safe
}};
const
marketSettings
=
{{
market_settings_json
|
safe
}};
...
@@ -114,7 +115,7 @@ function renderMarket() {
...
@@ -114,7 +115,7 @@ function renderMarket() {
}
}
async
function
importListing
(
id
)
{
async
function
importListing
(
id
)
{
const
response
=
await
fetch
(
`/api/market/listings/
${
id
}
/import`
,
{
method
:
'POST'
,
headers
:{
'Content-Type'
:
'application/json'
}});
const
response
=
await
fetch
(
`
${
BASE_PATH
}
/api/market/listings/
${
id
}
/import`
,
{
method
:
'POST'
,
headers
:{
'Content-Type'
:
'application/json'
}});
const
result
=
await
response
.
json
();
const
result
=
await
response
.
json
();
if
(
!
response
.
ok
)
{
if
(
!
response
.
ok
)
{
alert
(
result
.
error
||
'Import failed'
);
alert
(
result
.
error
||
'Import failed'
);
...
@@ -124,7 +125,7 @@ async function importListing(id) {
...
@@ -124,7 +125,7 @@ async function importListing(id) {
}
}
async
function
voteListing
(
id
,
targetType
,
vote
)
{
async
function
voteListing
(
id
,
targetType
,
vote
)
{
const
response
=
await
fetch
(
`/api/market/listings/
${
id
}
/vote`
,
{
const
response
=
await
fetch
(
`
${
BASE_PATH
}
/api/market/listings/
${
id
}
/vote`
,
{
method
:
'POST'
,
method
:
'POST'
,
headers
:{
'Content-Type'
:
'application/json'
},
headers
:{
'Content-Type'
:
'application/json'
},
body
:
JSON
.
stringify
({
target_type
:
targetType
,
vote
})
body
:
JSON
.
stringify
({
target_type
:
targetType
,
vote
})
...
@@ -150,7 +151,7 @@ async function publishListing() {
...
@@ -150,7 +151,7 @@ async function publishListing() {
price_per_million_tokens
:
parseFloat
(
document
.
getElementById
(
'publish-price-tokens'
).
value
||
'0'
),
price_per_million_tokens
:
parseFloat
(
document
.
getElementById
(
'publish-price-tokens'
).
value
||
'0'
),
price_per_1000_requests
:
parseFloat
(
document
.
getElementById
(
'publish-price-requests'
).
value
||
'0'
)
price_per_1000_requests
:
parseFloat
(
document
.
getElementById
(
'publish-price-requests'
).
value
||
'0'
)
};
};
const
response
=
await
fetch
(
'/api/market/listings'
,
{
const
response
=
await
fetch
(
`
${
BASE_PATH
}
/api/market/listings`
,
{
method
:
'POST'
,
method
:
'POST'
,
headers
:{
'Content-Type'
:
'application/json'
},
headers
:{
'Content-Type'
:
'application/json'
},
body
:
JSON
.
stringify
(
body
)
body
:
JSON
.
stringify
(
body
)
...
@@ -183,7 +184,7 @@ async function reloadMarket() {
...
@@ -183,7 +184,7 @@ async function reloadMarket() {
if
(
size
)
params
.
set
(
'size'
,
size
);
if
(
size
)
params
.
set
(
'size'
,
size
);
if
(
onlineOnly
)
params
.
set
(
'online_only'
,
'1'
);
if
(
onlineOnly
)
params
.
set
(
'online_only'
,
'1'
);
if
(
sortBy
)
params
.
set
(
'sort_by'
,
sortBy
);
if
(
sortBy
)
params
.
set
(
'sort_by'
,
sortBy
);
const
response
=
await
fetch
(
`/api/market/listings?
${
params
.
toString
()}
`
);
const
response
=
await
fetch
(
`
${
BASE_PATH
}
/api/market/listings?
${
params
.
toString
()}
`
);
const
result
=
await
response
.
json
();
const
result
=
await
response
.
json
();
if
(
!
response
.
ok
)
{
if
(
!
response
.
ok
)
{
alert
(
result
.
error
||
'Failed to load market'
);
alert
(
result
.
error
||
'Failed to load market'
);
...
...
templates/dashboard/providers.html
View file @
5bf3e58c
...
@@ -165,6 +165,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
...
@@ -165,6 +165,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
{% block extra_js %}
{% block extra_js %}
<script
src=
"{{ url_for(request, '/dashboard/static/dragsort.js') }}"
></script>
<script
src=
"{{ url_for(request, '/dashboard/static/dragsort.js') }}"
></script>
<script>
<script>
const
BASE_PATH
=
{{
(
request
.
scope
.
get
(
'root_path'
,
''
)
or
''
)
|
tojson
}};
function
escHtmlAttr
(
s
)
{
function
escHtmlAttr
(
s
)
{
return
String
(
s
).
replace
(
/&/g
,
'&'
).
replace
(
/</g
,
'<'
).
replace
(
/>/g
,
'>'
).
replace
(
/"/g
,
'"'
).
replace
(
/'/g
,
'''
);
return
String
(
s
).
replace
(
/&/g
,
'&'
).
replace
(
/</g
,
'<'
).
replace
(
/>/g
,
'>'
).
replace
(
/"/g
,
'"'
).
replace
(
/'/g
,
'''
);
}
}
...
@@ -3005,7 +3007,7 @@ async function saveProviders() {
...
@@ -3005,7 +3007,7 @@ async function saveProviders() {
if
(
response
.
ok
)
{
if
(
response
.
ok
)
{
sessionStorage
.
setItem
(
'providers_page'
,
currentProviderPage
);
sessionStorage
.
setItem
(
'providers_page'
,
currentProviderPage
);
window
.
location
.
href
=
BASE_PATH
+
'/dashboard/providers?success=1'
;
window
.
location
.
href
=
`
${
BASE_PATH
}
/dashboard/providers?success=1`
;
}
else
{
}
else
{
showAlert
(
window
.
i18n
.
t
(
'providers.error_saving'
),
'Error'
,
'❌'
,
'danger'
);
showAlert
(
window
.
i18n
.
t
(
'providers.error_saving'
),
'Error'
,
'❌'
,
'danger'
);
}
}
...
...
templates/dashboard/rotations.html
View file @
5bf3e58c
...
@@ -189,12 +189,12 @@ async function msOpenProvider(providerId, inputId, cb) {
...
@@ -189,12 +189,12 @@ async function msOpenProvider(providerId, inputId, cb) {
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'rotations.checking_models'
);
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'rotations.checking_models'
);
document
.
getElementById
(
'ms-results'
).
innerHTML
=
'<p style="color:var(--color-muted);text-align:center;padding:20px;">'
+
window
.
i18n
.
t
(
'rotations.loading'
)
+
'</p>'
;
document
.
getElementById
(
'ms-results'
).
innerHTML
=
'<p style="color:var(--color-muted);text-align:center;padding:20px;">'
+
window
.
i18n
.
t
(
'rotations.loading'
)
+
'</p>'
;
try
{
try
{
let
r
=
await
fetch
(
'/dashboard/providers/'
+
encodeURIComponent
(
providerId
)
+
'/configured-models'
);
let
r
=
await
fetch
(
`
${
BASE_PATH
}
/dashboard/providers/
${
encodeURIComponent
(
providerId
)}
/configured-models`
);
if
(
_msCancelled
)
return
;
if
(
_msCancelled
)
return
;
let
d
=
await
r
.
json
();
let
m
=
d
.
models
||
[];
let
d
=
await
r
.
json
();
let
m
=
d
.
models
||
[];
if
(
!
m
.
length
)
{
if
(
!
m
.
length
)
{
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'rotations.fetching_from_api'
);
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'rotations.fetching_from_api'
);
r
=
await
fetch
(
'/dashboard/providers/'
+
encodeURIComponent
(
providerId
)
+
'/search-models?refresh=true'
);
r
=
await
fetch
(
`
${
BASE_PATH
}
/dashboard/providers/
${
encodeURIComponent
(
providerId
)}
/search-models?refresh=true`
);
if
(
_msCancelled
)
return
;
if
(
_msCancelled
)
return
;
d
=
await
r
.
json
();
m
=
d
.
models
||
[];
d
=
await
r
.
json
();
m
=
d
.
models
||
[];
}
}
...
...
templates/dashboard/user_autoselects.html
View file @
5bf3e58c
...
@@ -97,7 +97,7 @@ async function msOpenAll(inputId, cb) {
...
@@ -97,7 +97,7 @@ async function msOpenAll(inputId, cb) {
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'autoselect.no_models_loaded'
);
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'autoselect.no_models_loaded'
);
document
.
getElementById
(
'ms-results'
).
innerHTML
=
`<p style="color:var(--color-muted);text-align:center;padding:20px;">
${
window
.
i18n
.
t
(
'autoselect.loading'
)}
</p>`
;
document
.
getElementById
(
'ms-results'
).
innerHTML
=
`<p style="color:var(--color-muted);text-align:center;padding:20px;">
${
window
.
i18n
.
t
(
'autoselect.loading'
)}
</p>`
;
try
{
try
{
const
r
=
await
fetch
(
'/dashboard/search-all-models?refresh=true'
);
const
r
=
await
fetch
(
`
${
BASE_PATH
}
/dashboard/search-all-models?refresh=true`
);
if
(
_msCancelled
)
return
;
if
(
_msCancelled
)
return
;
const
data
=
await
r
.
json
();
const
fetched
=
data
.
models
||
[];
const
data
=
await
r
.
json
();
const
fetched
=
data
.
models
||
[];
_msAllItems
=
fetched
;
_msAllItems
=
fetched
;
...
...
templates/dashboard/user_providers.html
View file @
5bf3e58c
...
@@ -2703,7 +2703,7 @@ async function saveProviders() {
...
@@ -2703,7 +2703,7 @@ async function saveProviders() {
});
});
if
(
response
.
ok
)
{
if
(
response
.
ok
)
{
window
.
location
.
href
=
BASE_PATH
+
'/dashboard/providers?success=1'
;
window
.
location
.
href
=
`
${
BASE_PATH
}
/dashboard/providers?success=1`
;
}
else
{
}
else
{
showAlert
(
window
.
i18n
.
t
(
'providers.error_saving'
),
'Error'
,
'❌'
,
'danger'
);
showAlert
(
window
.
i18n
.
t
(
'providers.error_saving'
),
'Error'
,
'❌'
,
'danger'
);
}
}
...
...
templates/dashboard/user_rotations.html
View file @
5bf3e58c
...
@@ -182,12 +182,12 @@ async function msOpenProvider(providerId, inputId, cb) {
...
@@ -182,12 +182,12 @@ async function msOpenProvider(providerId, inputId, cb) {
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'rotations.checking_models'
);
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'rotations.checking_models'
);
document
.
getElementById
(
'ms-results'
).
innerHTML
=
'<p style="color:var(--color-muted);text-align:center;padding:20px;">'
+
window
.
i18n
.
t
(
'rotations.loading'
)
+
'</p>'
;
document
.
getElementById
(
'ms-results'
).
innerHTML
=
'<p style="color:var(--color-muted);text-align:center;padding:20px;">'
+
window
.
i18n
.
t
(
'rotations.loading'
)
+
'</p>'
;
try
{
try
{
let
r
=
await
fetch
(
'/dashboard/providers/'
+
encodeURIComponent
(
providerId
)
+
'/configured-models'
);
let
r
=
await
fetch
(
`
${
BASE_PATH
}
/dashboard/providers/
${
encodeURIComponent
(
providerId
)}
/configured-models`
);
if
(
_msCancelled
)
return
;
if
(
_msCancelled
)
return
;
let
d
=
await
r
.
json
();
let
m
=
d
.
models
||
[];
let
d
=
await
r
.
json
();
let
m
=
d
.
models
||
[];
if
(
!
m
.
length
)
{
if
(
!
m
.
length
)
{
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'rotations.fetching_from_api'
);
document
.
getElementById
(
'ms-status'
).
textContent
=
window
.
i18n
.
t
(
'rotations.fetching_from_api'
);
r
=
await
fetch
(
'/dashboard/providers/'
+
encodeURIComponent
(
providerId
)
+
'/search-models?refresh=true'
);
r
=
await
fetch
(
`
${
BASE_PATH
}
/dashboard/providers/
${
encodeURIComponent
(
providerId
)}
/search-models?refresh=true`
);
if
(
_msCancelled
)
return
;
if
(
_msCancelled
)
return
;
d
=
await
r
.
json
();
m
=
d
.
models
||
[];
d
=
await
r
.
json
();
m
=
d
.
models
||
[];
}
}
...
...
tests/routes/test_dashboard_proxy_awareness.py
0 → 100644
View file @
5bf3e58c
import
json
import
sys
from
base64
import
b64encode
from
pathlib
import
Path
from
fastapi.responses
import
HTMLResponse
from
fastapi.testclient
import
TestClient
from
itsdangerous
import
TimestampSigner
from
jinja2
import
Environment
,
FileSystemLoader
,
select_autoescape
from
aisbf.routes.dashboard
import
market
as
dashboard_market
sys
.
path
.
insert
(
0
,
str
(
Path
(
__file__
)
.
resolve
()
.
parents
[
2
]))
from
main
import
app
class
TemplateCapture
:
def
__init__
(
self
):
self
.
calls
=
[]
self
.
_env
=
Environment
(
loader
=
FileSystemLoader
(
str
(
Path
(
__file__
)
.
resolve
()
.
parents
[
2
]
/
"templates"
)),
autoescape
=
select_autoescape
([
"html"
,
"xml"
]),
)
self
.
_env
.
globals
[
"url_for"
]
=
lambda
request
,
path
,
**
kwargs
:
path
def
TemplateResponse
(
self
,
*
args
,
**
kwargs
):
request
=
kwargs
[
"request"
]
name
=
kwargs
[
"name"
]
context
=
kwargs
[
"context"
]
self
.
calls
.
append
({
"request"
:
request
,
"name"
:
name
,
"context"
:
context
})
template
=
self
.
_env
.
get_template
(
name
)
return
HTMLResponse
(
template
.
render
(
**
context
))
class
DashboardProxyDbStub
:
def
__init__
(
self
):
self
.
market_settings
=
{
"enabled"
:
True
,
"allow_user_publish"
:
True
,
"allow_admin_publish"
:
True
,
"allow_import"
:
True
,
}
self
.
reference_rows
=
[]
self
.
user_providers
=
[
{
"provider_id"
:
"local-provider"
,
"config"
:
{
"name"
:
"Local Provider"
,
"type"
:
"openai"
,
"models"
:
[]},
"created_at"
:
None
,
"updated_at"
:
None
,
}
]
self
.
user_rotations
=
[
{
"rotation_id"
:
"local-rotation"
,
"config"
:
{
"model_name"
:
"Local Rotation"
,
"providers"
:
[]},
}
]
self
.
user_autoselects
=
[
{
"autoselect_id"
:
"local-autoselect"
,
"config"
:
{
"model_name"
:
"Local Autoselect"
,
"description"
:
"Local chooser"
,
"selection_model"
:
"internal"
,
"fallback"
:
""
,
"available_models"
:
[],
},
}
]
self
.
market_listings
=
[
{
"id"
:
55
,
"owner_user_id"
:
7
,
"owner_username"
:
"seller"
,
"source_scope"
:
"user"
,
"source_type"
:
"provider"
,
"source_id"
:
"seller-provider"
,
"listing_key"
:
"provider:seller-provider"
,
"title"
:
"Seller Provider"
,
"description"
:
"Shared provider"
,
"provider_id"
:
"seller-provider"
,
"model_id"
:
None
,
"endpoint"
:
"https://seller.example/v1"
,
"price_per_million_tokens"
:
1.0
,
"price_per_1000_requests"
:
0.2
,
"provider_price_per_million_tokens"
:
1.0
,
"provider_price_per_1000_requests"
:
0.2
,
"currency_code"
:
"USD"
,
"metadata"
:
{
"provider_type"
:
"openai"
,
"capabilities"
:
[
"chat"
]},
"stats"
:
{
"usage_events"
:
1
,
"total_requests"
:
2
,
"total_tokens"
:
3
,
"avg_tokens_per_request"
:
1.5
,
"gross_revenue"
:
4.0
,
"provider_revenue"
:
2.0
},
"analytics"
:
{
"request_count"
:
2
,
"avg_latency_ms"
:
123.0
,
"error_rate"
:
0.0
,
"total_tokens"
:
3
},
"is_active"
:
True
,
}
]
def
get_market_settings
(
self
):
return
dict
(
self
.
market_settings
)
def
list_market_import_references
(
self
,
user_id
):
return
[
dict
(
row
)
for
row
in
self
.
reference_rows
if
row
[
"user_id"
]
==
user_id
]
def
get_sort_order
(
self
,
user_id
,
resource_type
):
return
None
def
get_user_providers
(
self
,
user_id
):
return
[
dict
(
row
)
for
row
in
self
.
user_providers
]
def
get_user_rotations
(
self
,
user_id
):
return
[
dict
(
row
)
for
row
in
self
.
user_rotations
]
def
get_user_autoselects
(
self
,
user_id
):
return
[
dict
(
row
)
for
row
in
self
.
user_autoselects
]
def
list_market_listings
(
self
,
active_only
=
False
):
return
[
dict
(
row
)
for
row
in
self
.
market_listings
]
def
get_provider_disabled_until
(
self
,
owner_user_id
,
provider_id
):
return
None
def
get_provider_usage
(
self
,
owner_user_id
,
provider_id
):
return
{
"usage_data"
:
{
"ok"
:
True
}}
def
get_user_by_id
(
self
,
user_id
):
if
user_id
==
7
:
return
{
"id"
:
7
,
"username"
:
"seller"
,
"display_name"
:
"Seller"
}
if
user_id
==
11
:
return
{
"id"
:
11
,
"username"
:
"buyer"
,
"display_name"
:
"Buyer"
}
return
None
def
get_currency_settings
(
self
):
return
{
"currency_symbol"
:
"$"
}
def
get_market_vote_summary
(
self
,
listing_id
):
return
{
"listing"
:
{
"upvotes"
:
0
,
"downvotes"
:
0
,
"score"
:
0
},
"provider"
:
{
"upvotes"
:
0
,
"downvotes"
:
0
,
"score"
:
0
},
"model"
:
{
"upvotes"
:
0
,
"downvotes"
:
0
,
"score"
:
0
},
"user"
:
{
"upvotes"
:
0
,
"downvotes"
:
0
,
"score"
:
0
},
}
def
get_market_listing_stats
(
self
,
listing_id
):
return
{
"gross_revenue"
:
4.0
,
"total_requests"
:
2
}
class
RegistryStub
:
def
__init__
(
self
,
db
):
self
.
_db
=
db
def
get_config_database
(
self
):
return
self
.
_db
def
_find_session_secret
()
->
str
:
for
middleware
in
app
.
user_middleware
:
kwargs
=
getattr
(
middleware
,
"kwargs"
,
{})
secret_key
=
kwargs
.
get
(
"secret_key"
)
if
secret_key
:
return
secret_key
raise
AssertionError
(
"Session middleware secret key not found"
)
def
_set_session_cookie
(
client
:
TestClient
,
data
:
dict
)
->
None
:
signer
=
TimestampSigner
(
_find_session_secret
())
serialized
=
b64encode
(
json
.
dumps
(
data
)
.
encode
(
"utf-8"
))
signed
=
signer
.
sign
(
serialized
)
.
decode
(
"utf-8"
)
client
.
cookies
.
set
(
"session"
,
signed
)
def
_login_as_user
(
client
:
TestClient
,
user_id
:
int
=
11
)
->
None
:
_set_session_cookie
(
client
,
{
"logged_in"
:
True
,
"username"
:
"buyer"
,
"role"
:
"user"
,
"user_id"
:
user_id
,
"expires_at"
:
4102444800
,
},
)
def
_forwarded_prefix_headers
():
return
{
"X-Forwarded-Prefix"
:
"/proxy/app"
,
"X-Forwarded-Host"
:
"example.test"
,
"X-Forwarded-Proto"
:
"https"
,
}
def
test_user_providers_page_uses_proxy_aware_bootstrap_paths
(
monkeypatch
):
db
=
DashboardProxyDbStub
()
capture
=
TemplateCapture
()
client
=
TestClient
(
app
)
_login_as_user
(
client
)
monkeypatch
.
setattr
(
dashboard_market
,
"DatabaseRegistry"
,
RegistryStub
(
db
))
from
aisbf.routes.dashboard
import
providers
as
dashboard_providers
monkeypatch
.
setattr
(
dashboard_providers
,
"DatabaseRegistry"
,
RegistryStub
(
db
))
monkeypatch
.
setattr
(
dashboard_providers
,
"_templates"
,
capture
)
response
=
client
.
get
(
"/dashboard/providers"
,
headers
=
_forwarded_prefix_headers
())
assert
response
.
status_code
==
200
assert
'const BASE_PATH = "/proxy/app"'
in
response
.
text
assert
'window.location.href = `${BASE_PATH}/dashboard/providers?success=1`;'
in
response
.
text
assert
"window.location.href = '/dashboard/providers?success=1'"
not
in
response
.
text
def
test_user_rotations_page_uses_proxy_aware_search_urls
(
monkeypatch
):
db
=
DashboardProxyDbStub
()
capture
=
TemplateCapture
()
client
=
TestClient
(
app
)
_login_as_user
(
client
)
monkeypatch
.
setattr
(
dashboard_market
,
"DatabaseRegistry"
,
RegistryStub
(
db
))
from
aisbf.routes.dashboard
import
providers
as
dashboard_providers
monkeypatch
.
setattr
(
dashboard_providers
,
"DatabaseRegistry"
,
RegistryStub
(
db
))
monkeypatch
.
setattr
(
dashboard_providers
,
"_templates"
,
capture
)
response
=
client
.
get
(
"/dashboard/rotations"
,
headers
=
_forwarded_prefix_headers
())
assert
response
.
status_code
==
200
assert
'const BASE_PATH = "/proxy/app"'
in
response
.
text
assert
"fetch(`${BASE_PATH}/dashboard/providers/"
in
response
.
text
assert
"fetch('/dashboard/providers/"
not
in
response
.
text
def
test_market_page_uses_proxy_aware_market_api_urls
(
monkeypatch
):
db
=
DashboardProxyDbStub
()
capture
=
TemplateCapture
()
client
=
TestClient
(
app
)
_login_as_user
(
client
)
monkeypatch
.
setattr
(
dashboard_market
,
"DatabaseRegistry"
,
RegistryStub
(
db
))
monkeypatch
.
setattr
(
dashboard_market
,
"_templates"
,
capture
)
response
=
client
.
get
(
"/dashboard/market"
,
headers
=
_forwarded_prefix_headers
())
assert
response
.
status_code
==
200
assert
'const BASE_PATH = "/proxy/app"'
in
response
.
text
assert
"fetch(`${BASE_PATH}/api/market/listings`"
in
response
.
text
assert
"fetch('/api/market/listings'"
not
in
response
.
text
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment