mirror of
https://github.com/rustmailer/bichon.git
synced 2026-08-03 07:48:34 +02:00
feat: Allow to host under subpath #145
This commit is contained in:
+30
-7
@@ -37,8 +37,8 @@ use http::{HeaderValue, Method};
|
|||||||
use poem::endpoint::EmbeddedFilesEndpoint;
|
use poem::endpoint::EmbeddedFilesEndpoint;
|
||||||
use poem::listener::{Listener, TcpListener};
|
use poem::listener::{Listener, TcpListener};
|
||||||
use poem::middleware::{CatchPanic, Compression, SetHeader};
|
use poem::middleware::{CatchPanic, Compression, SetHeader};
|
||||||
use poem::{endpoint::EmbeddedFileEndpoint, middleware::Cors, EndpointExt, Route, Server};
|
use poem::{get, handler, post, IntoResponse};
|
||||||
use poem::{get, post};
|
use poem::{middleware::Cors, EndpointExt, Route, Server};
|
||||||
use public::oauth2::oauth2_callback;
|
use public::oauth2::oauth2_callback;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -115,7 +115,7 @@ pub async fn start_http_server() -> BichonResult<()> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let route = Route::new()
|
let app_logic = Route::new()
|
||||||
.nest("/api-docs/swagger", swagger)
|
.nest("/api-docs/swagger", swagger)
|
||||||
.nest("/api-docs/redoc", redoc)
|
.nest("/api-docs/redoc", redoc)
|
||||||
.nest("/api-docs/explorer", openapi_explorer)
|
.nest("/api-docs/explorer", openapi_explorer)
|
||||||
@@ -130,10 +130,10 @@ pub async fn start_http_server() -> BichonResult<()> {
|
|||||||
"/assets",
|
"/assets",
|
||||||
EmbeddedFilesEndpoint::<FrontEndAssets>::new().with(cache_static()),
|
EmbeddedFilesEndpoint::<FrontEndAssets>::new().with(cache_static()),
|
||||||
)
|
)
|
||||||
.at(
|
.at("/*", serve_index_with_base);
|
||||||
"/*",
|
|
||||||
EmbeddedFileEndpoint::<FrontEndAssets>::new("index.html"),
|
let route = Route::new()
|
||||||
)
|
.nest(&SETTINGS.bichon_base_url, app_logic)
|
||||||
.with(cors)
|
.with(cors)
|
||||||
.with_if(SETTINGS.bichon_http_compression_enabled, Compression::new())
|
.with_if(SETTINGS.bichon_http_compression_enabled, Compression::new())
|
||||||
.with(CatchPanic::new());
|
.with(CatchPanic::new());
|
||||||
@@ -158,3 +158,26 @@ pub async fn start_http_server() -> BichonResult<()> {
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))
|
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[handler]
|
||||||
|
async fn serve_index_with_base() -> impl IntoResponse {
|
||||||
|
let mut html =
|
||||||
|
String::from_utf8_lossy(&FrontEndAssets::get("index.html").unwrap().data).to_string();
|
||||||
|
|
||||||
|
let raw_base = &SETTINGS.bichon_base_url;
|
||||||
|
let base_href = if raw_base.ends_with('/') {
|
||||||
|
raw_base.clone()
|
||||||
|
} else {
|
||||||
|
format!("{}/", raw_base)
|
||||||
|
};
|
||||||
|
|
||||||
|
let inject_content = format!(
|
||||||
|
r#"<base href="{}"><script>window.__BICHON_BASE__ = '{}';</script>"#,
|
||||||
|
base_href, raw_base
|
||||||
|
);
|
||||||
|
|
||||||
|
html = html.replace("<head>", &format!("<head>{}", inject_content));
|
||||||
|
poem::Response::builder()
|
||||||
|
.content_type("text/html; charset=utf-8")
|
||||||
|
.body(html)
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,6 +74,16 @@ pub struct Settings {
|
|||||||
)]
|
)]
|
||||||
pub bichon_public_url: String,
|
pub bichon_public_url: String,
|
||||||
|
|
||||||
|
/// bichon base URL path (default: "/")
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
default_value = "/",
|
||||||
|
env,
|
||||||
|
help = "Set the base UI path for bichon (e.g., '/bichon' or '/bichon/'). Must start with /",
|
||||||
|
value_parser = validate_base_url
|
||||||
|
)]
|
||||||
|
pub bichon_base_url: String,
|
||||||
|
|
||||||
/// CORS allowed origins (default: "*")
|
/// CORS allowed origins (default: "*")
|
||||||
#[clap(
|
#[clap(
|
||||||
long,
|
long,
|
||||||
@@ -381,6 +391,18 @@ impl Settings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_base_url(s: &str) -> Result<String, String> {
|
||||||
|
if s == "/" {
|
||||||
|
return Ok(s.to_string());
|
||||||
|
}
|
||||||
|
if !s.starts_with('/') {
|
||||||
|
return Err(String::from(
|
||||||
|
"Base URL must start with '/' (e.g., '/bichon')",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(s.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, ValueEnum)]
|
#[derive(Clone, Copy, Debug, PartialEq, ValueEnum)]
|
||||||
pub enum CompressionAlgorithm {
|
pub enum CompressionAlgorithm {
|
||||||
#[clap(name = "none")]
|
#[clap(name = "none")]
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export interface MinimalAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const minimal_account_list = async () => {
|
export const minimal_account_list = async () => {
|
||||||
const response = await axiosInstance.get<MinimalAccount[]>("/api/v1/minimal-account-list");
|
const response = await axiosInstance.get<MinimalAccount[]>("api/v1/minimal-account-list");
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -109,27 +109,27 @@ export interface AccountModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const account_state = async (account_id: number) => {
|
export const account_state = async (account_id: number) => {
|
||||||
const response = await axiosInstance.get<AccountRunningState>(`/api/v1/account-state/${account_id}`);
|
const response = await axiosInstance.get<AccountRunningState>(`api/v1/account-state/${account_id}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const create_account = async (data: Record<string, any>) => {
|
export const create_account = async (data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post("/api/v1/account", data);
|
const response = await axiosInstance.post("api/v1/account", data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const list_accounts = async () => {
|
export const list_accounts = async () => {
|
||||||
const response = await axiosInstance.get<PaginatedResponse<AccountModel>>("/api/v1/accounts?desc=true");
|
const response = await axiosInstance.get<PaginatedResponse<AccountModel>>("api/v1/accounts?desc=true");
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const update_account = async (account_id: number, data: Record<string, any>) => {
|
export const update_account = async (account_id: number, data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post(`/api/v1/account/${account_id}`, data);
|
const response = await axiosInstance.post(`api/v1/account/${account_id}`, data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const remove_account = async (account_id: number) => {
|
export const remove_account = async (account_id: number) => {
|
||||||
const response = await axiosInstance.delete(`/api/v1/account/${account_id}`);
|
const response = await axiosInstance.delete(`api/v1/account/${account_id}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -152,11 +152,11 @@ export interface OAuth2Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const autoconfig = async (email: string) => {
|
export const autoconfig = async (email: string) => {
|
||||||
const response = await axiosInstance.get<AutoConfigResult>(`/api/v1/autoconfig/${email}`);
|
const response = await axiosInstance.get<AutoConfigResult>(`api/v1/autoconfig/${email}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const access_assign = async (data: Record<string, any>) => {
|
export const access_assign = async (data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post("/api/v1/accounts/access/assignments", data);
|
const response = await axiosInstance.post("api/v1/accounts/access/assignments", data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
@@ -20,9 +20,13 @@
|
|||||||
import { getToken } from "@/stores/authStore";
|
import { getToken } from "@/stores/authStore";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
|
const injectedBase = (window as any).__BICHON_BASE__;
|
||||||
|
const base_url = (injectedBase === "/" || !injectedBase) ? "" : injectedBase;
|
||||||
|
|
||||||
|
|
||||||
// Create an Axios instance
|
// Create an Axios instance
|
||||||
const baseURL = process.env.NODE_ENV === "production"
|
const baseURL = process.env.NODE_ENV === "production"
|
||||||
? "/" // Production: relative to the current domain
|
? base_url // Production: relative to the current domain
|
||||||
: "http://localhost:15630"; // Development: Poem's backend server
|
: "http://localhost:15630"; // Development: Poem's backend server
|
||||||
|
|
||||||
const axiosInstance = axios.create({
|
const axiosInstance = axios.create({
|
||||||
|
|||||||
@@ -33,12 +33,12 @@ export interface MailboxData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const list_mailboxes = async (accountId: number, remote: boolean) => {
|
export const list_mailboxes = async (accountId: number, remote: boolean) => {
|
||||||
const response = await axiosInstance.get<MailboxData[]>(`/api/v1/list-mailboxes/${accountId}?remote=${remote}`);
|
const response = await axiosInstance.get<MailboxData[]>(`api/v1/list-mailboxes/${accountId}?remote=${remote}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const delete_mailbox = async (accountId: number, mailboxId: string) => {
|
export const delete_mailbox = async (accountId: number, mailboxId: string) => {
|
||||||
const response = await axiosInstance.delete(`/api/v1/delete-mailbox/${accountId}/${mailboxId}`);
|
const response = await axiosInstance.delete(`api/v1/delete-mailbox/${accountId}/${mailboxId}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
@@ -29,7 +29,7 @@ export const list_messages = async (accountId: number, mailbox_id: number, page:
|
|||||||
});
|
});
|
||||||
|
|
||||||
const response = await axiosInstance.get<PaginatedResponse<EmailEnvelope>>(
|
const response = await axiosInstance.get<PaginatedResponse<EmailEnvelope>>(
|
||||||
`/api/v1/list-messages/${accountId}?${params.toString()}`
|
`api/v1/list-messages/${accountId}?${params.toString()}`
|
||||||
);
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
@@ -42,13 +42,13 @@ export const get_thread_messages = async (accountId: number, thread_id: number,
|
|||||||
});
|
});
|
||||||
|
|
||||||
const response = await axiosInstance.get<PaginatedResponse<EmailEnvelope>>(
|
const response = await axiosInstance.get<PaginatedResponse<EmailEnvelope>>(
|
||||||
`/api/v1/get-thread-messages/${accountId}?${params.toString()}`
|
`api/v1/get-thread-messages/${accountId}?${params.toString()}`
|
||||||
);
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const download_attachment = async (accountId: number, id: number, attachmentFileName: string) => {
|
export const download_attachment = async (accountId: number, id: number, attachmentFileName: string) => {
|
||||||
const response = await axiosInstance.get(`/api/v1/download-attachment/${accountId}/${id}?name=${attachmentFileName}`, { responseType: 'blob' });
|
const response = await axiosInstance.get(`api/v1/download-attachment/${accountId}/${id}?name=${attachmentFileName}`, { responseType: 'blob' });
|
||||||
const blob = new Blob([response.data]);
|
const blob = new Blob([response.data]);
|
||||||
saveAs(blob, attachmentFileName);
|
saveAs(blob, attachmentFileName);
|
||||||
};
|
};
|
||||||
@@ -83,17 +83,17 @@ export const getContent = (messageContent: MessageContentResponse): string | nul
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const load_message = async (accountId: number, id: number) => {
|
export const load_message = async (accountId: number, id: number) => {
|
||||||
const response = await axiosInstance.get<MessageContentResponse>(`/api/v1/message-content/${accountId}/${id}`);
|
const response = await axiosInstance.get<MessageContentResponse>(`api/v1/message-content/${accountId}/${id}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const delete_messages = async (payload: Record<string, number[]>) => {
|
export const delete_messages = async (payload: Record<string, number[]>) => {
|
||||||
const response = await axiosInstance.post("/api/v1/delete-messages", payload);
|
const response = await axiosInstance.post("api/v1/delete-messages", payload);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const download_message = async (accountId: number, id: number) => {
|
export const download_message = async (accountId: number, id: number) => {
|
||||||
const response = await axiosInstance.get(`/api/v1/download-message/${accountId}/${id}`, { responseType: 'blob' });
|
const response = await axiosInstance.get(`api/v1/download-message/${accountId}/${id}`, { responseType: 'blob' });
|
||||||
const blob = new Blob([response.data]);
|
const blob = new Blob([response.data]);
|
||||||
saveAs(blob, `${id}.eml`);
|
saveAs(blob, `${id}.eml`);
|
||||||
};
|
};
|
||||||
@@ -101,7 +101,7 @@ export const download_message = async (accountId: number, id: number) => {
|
|||||||
|
|
||||||
|
|
||||||
export const restore_message = async (accountId: number, messageIds: number[]) => {
|
export const restore_message = async (accountId: number, messageIds: number[]) => {
|
||||||
const response = await axiosInstance.post(`/api/v1/restore-messages/${accountId}`, {
|
const response = await axiosInstance.post(`api/v1/restore-messages/${accountId}`, {
|
||||||
message_ids: messageIds,
|
message_ids: messageIds,
|
||||||
});
|
});
|
||||||
return response.data;
|
return response.data;
|
||||||
|
|||||||
@@ -21,28 +21,28 @@ import { OAuth2Entity } from "@/features/oauth2/data/schema";
|
|||||||
import axiosInstance from "../axiosInstance";
|
import axiosInstance from "../axiosInstance";
|
||||||
|
|
||||||
export const get_oauth2_list = async () => {
|
export const get_oauth2_list = async () => {
|
||||||
const response = await axiosInstance.get<{ items: OAuth2Entity[] }>("/api/v1/oauth2-list");
|
const response = await axiosInstance.get<{ items: OAuth2Entity[] }>("api/v1/oauth2-list");
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const delete_oauth2 = async (id: number) => {
|
export const delete_oauth2 = async (id: number) => {
|
||||||
const response = await axiosInstance.delete(`/api/v1/oauth2/${id}`);
|
const response = await axiosInstance.delete(`api/v1/oauth2/${id}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const create_oauth2 = async (data: Record<string, any>) => {
|
export const create_oauth2 = async (data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post<OAuth2Entity>("/api/v1/oauth2", data);
|
const response = await axiosInstance.post<OAuth2Entity>("api/v1/oauth2", data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const update_oauth2 = async (id: number, data: Record<string, any>) => {
|
export const update_oauth2 = async (id: number, data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post<OAuth2Entity>(`/api/v1/oauth2/${id}`, data);
|
const response = await axiosInstance.post<OAuth2Entity>(`api/v1/oauth2/${id}`, data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const get_authorize_url = async (data: Record<string, any>) => {
|
export const get_authorize_url = async (data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post('/api/v1/oauth2-authorize-url', data);
|
const response = await axiosInstance.post('api/v1/oauth2-authorize-url', data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -57,6 +57,6 @@ export interface OAuth2Tokens {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const get_oauth2_tokens = async (accountId: number) => {
|
export const get_oauth2_tokens = async (accountId: number) => {
|
||||||
const response = await axiosInstance.get<OAuth2Tokens>(`/api/v1/oauth2-tokens/${accountId}`);
|
const response = await axiosInstance.get<OAuth2Tokens>(`api/v1/oauth2-tokens/${accountId}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
@@ -21,7 +21,7 @@ import axiosInstance from "@/api/axiosInstance";
|
|||||||
import { EmailEnvelope, PaginatedResponse } from "..";
|
import { EmailEnvelope, PaginatedResponse } from "..";
|
||||||
|
|
||||||
export const search_messages = async (payload: Record<string, any>) => {
|
export const search_messages = async (payload: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post<PaginatedResponse<EmailEnvelope>>("/api/v1/search-messages", payload);
|
const response = await axiosInstance.post<PaginatedResponse<EmailEnvelope>>("api/v1/search-messages", payload);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -31,18 +31,18 @@ export interface TagCount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const get_tags = async () => {
|
export const get_tags = async () => {
|
||||||
const response = await axiosInstance.get<TagCount[]>("/api/v1/all-tags");
|
const response = await axiosInstance.get<TagCount[]>("api/v1/all-tags");
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const update_tags = async (data: Record<string, any>) => {
|
export const update_tags = async (data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post("/api/v1/update-tags", data);
|
const response = await axiosInstance.post("api/v1/update-tags", data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const get_contacts = async () => {
|
export const get_contacts = async () => {
|
||||||
const response = await axiosInstance.get<string[]>("/api/v1/all-contacts");
|
const response = await axiosInstance.get<string[]>("api/v1/all-contacts");
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ interface Notifications {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const get_notifications = async () => {
|
export const get_notifications = async () => {
|
||||||
const response = await axiosInstance.get<Notifications>(`/api/v1/notifications`);
|
const response = await axiosInstance.get<Notifications>(`api/v1/notifications`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -118,22 +118,22 @@ export type ServerConfigurations = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const get_dashboard_stats = async () => {
|
export const get_dashboard_stats = async () => {
|
||||||
const response = await axiosInstance.get<DashboardStats>(`/api/v1/dashboard-stats`);
|
const response = await axiosInstance.get<DashboardStats>(`api/v1/dashboard-stats`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const list_proxy = async () => {
|
export const list_proxy = async () => {
|
||||||
const response = await axiosInstance.get<Proxy[]>(`/api/v1/list-proxy`);
|
const response = await axiosInstance.get<Proxy[]>(`api/v1/list-proxy`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const delete_proxy = async (id: number) => {
|
export const delete_proxy = async (id: number) => {
|
||||||
const response = await axiosInstance.delete(`/api/v1/proxy/${id}`);
|
const response = await axiosInstance.delete(`api/v1/proxy/${id}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const update_proxy = async (id: number, url: string) => {
|
export const update_proxy = async (id: number, url: string) => {
|
||||||
const response = await axiosInstance.post(`/api/v1/proxy/${id}`, url, {
|
const response = await axiosInstance.post(`api/v1/proxy/${id}`, url, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "text/plain",
|
"Content-Type": "text/plain",
|
||||||
},
|
},
|
||||||
@@ -142,7 +142,7 @@ export const update_proxy = async (id: number, url: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const add_proxy = async (url: string) => {
|
export const add_proxy = async (url: string) => {
|
||||||
const response = await axiosInstance.post(`/api/v1/proxy`, url, {
|
const response = await axiosInstance.post(`api/v1/proxy`, url, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "text/plain",
|
"Content-Type": "text/plain",
|
||||||
},
|
},
|
||||||
@@ -152,6 +152,6 @@ export const add_proxy = async (url: string) => {
|
|||||||
|
|
||||||
|
|
||||||
export const get_system_configurations = async () => {
|
export const get_system_configurations = async () => {
|
||||||
const response = await axiosInstance.get<ServerConfigurations>(`/api/v1/system-configurations`);
|
const response = await axiosInstance.get<ServerConfigurations>(`api/v1/system-configurations`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
+19
-19
@@ -125,17 +125,17 @@ export interface MinimalUser {
|
|||||||
|
|
||||||
|
|
||||||
export const login = async (data: Record<string, any>) => {
|
export const login = async (data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post<LoginResult>(`/api/login`, data);
|
const response = await axiosInstance.post<LoginResult>(`api/login`, data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reset_admin_token = async () => {
|
export const reset_admin_token = async () => {
|
||||||
const response = await axiosInstance.post("/api/v1/reset-admin-token");
|
const response = await axiosInstance.post("api/v1/reset-admin-token");
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reset_admin_password = async (password: string) => {
|
export const reset_admin_password = async (password: string) => {
|
||||||
const response = await axiosInstance.post("/api/v1/reset-admin-password", password, {
|
const response = await axiosInstance.post("api/v1/reset-admin-password", password, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "text/plain",
|
"Content-Type": "text/plain",
|
||||||
},
|
},
|
||||||
@@ -144,89 +144,89 @@ export const reset_admin_password = async (password: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const list_access_tokens = async () => {
|
export const list_access_tokens = async () => {
|
||||||
const response = await axiosInstance.get<AccessToken[]>("/api/v1/access-token-list");
|
const response = await axiosInstance.get<AccessToken[]>("api/v1/access-token-list");
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const create_access_token = async (data: Record<string, any>) => {
|
export const create_access_token = async (data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post("/api/v1/access-token", data);
|
const response = await axiosInstance.post("api/v1/access-token", data);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const update_access_token = async (token: string, data: Record<string, any>) => {
|
export const update_access_token = async (token: string, data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post(`/api/v1/access-token/${token}`, data);
|
const response = await axiosInstance.post(`api/v1/access-token/${token}`, data);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const remove_access_token = async (token: string) => {
|
export const remove_access_token = async (token: string) => {
|
||||||
const response = await axiosInstance.delete(`/api/v1/access-token/${token}`);
|
const response = await axiosInstance.delete(`api/v1/access-token/${token}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const list_roles = async () => {
|
export const list_roles = async () => {
|
||||||
const response = await axiosInstance.get<UserRole[]>("/api/v1/list-roles");
|
const response = await axiosInstance.get<UserRole[]>("api/v1/list-roles");
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const remove_role = async (id: number) => {
|
export const remove_role = async (id: number) => {
|
||||||
const response = await axiosInstance.delete(`/api/v1/roles/${id}`);
|
const response = await axiosInstance.delete(`api/v1/roles/${id}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const create_role = async (data: Record<string, any>) => {
|
export const create_role = async (data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post("/api/v1/roles", data);
|
const response = await axiosInstance.post("api/v1/roles", data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const update_role = async (id: number, data: Record<string, any>) => {
|
export const update_role = async (id: number, data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post(`/api/v1/roles/${id}`, data);
|
const response = await axiosInstance.post(`api/v1/roles/${id}`, data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const list_users = async () => {
|
export const list_users = async () => {
|
||||||
const response = await axiosInstance.get<User[]>("/api/v1/list-users");
|
const response = await axiosInstance.get<User[]>("api/v1/list-users");
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const list_minimal_users = async () => {
|
export const list_minimal_users = async () => {
|
||||||
const response = await axiosInstance.get<MinimalUser[]>("/api/v1/minimal-user-list");
|
const response = await axiosInstance.get<MinimalUser[]>("api/v1/minimal-user-list");
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const list_account_roles = async () => {
|
export const list_account_roles = async () => {
|
||||||
const response = await axiosInstance.get<UserRole[]>("/api/v1/list-account-roles");
|
const response = await axiosInstance.get<UserRole[]>("api/v1/list-account-roles");
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const remove_user = async (id: number) => {
|
export const remove_user = async (id: number) => {
|
||||||
const response = await axiosInstance.delete(`/api/v1/users/${id}`);
|
const response = await axiosInstance.delete(`api/v1/users/${id}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const create_user = async (data: Record<string, any>) => {
|
export const create_user = async (data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post("/api/v1/users", data);
|
const response = await axiosInstance.post("api/v1/users", data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const update_user = async (id: number, data: Record<string, any>) => {
|
export const update_user = async (id: number, data: Record<string, any>) => {
|
||||||
const response = await axiosInstance.post(`/api/v1/users/${id}`, data);
|
const response = await axiosInstance.post(`api/v1/users/${id}`, data);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const get_user_tokens = async (id: number) => {
|
export const get_user_tokens = async (id: number) => {
|
||||||
const response = await axiosInstance.get<AccessToken[]>(`/api/v1/user-tokens/${id}`);
|
const response = await axiosInstance.get<AccessToken[]>(`api/v1/user-tokens/${id}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const get_current_user = async () => {
|
export const get_current_user = async () => {
|
||||||
const response = await axiosInstance.get<User>("/api/v1/current-user");
|
const response = await axiosInstance.get<User>("api/v1/current-user");
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,12 +27,14 @@ import { Separator } from "./ui/separator";
|
|||||||
export default function APIDocs() {
|
export default function APIDocs() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const base_url = (window as any).__BICHON_BASE__ || '';
|
||||||
|
|
||||||
const docsOptions = [
|
const docsOptions = [
|
||||||
{ name: t('apiDocs.swaggerUI'), path: "/api-docs/swagger" },
|
{ name: t('apiDocs.swaggerUI'), path: `${base_url}/api-docs/swagger` },
|
||||||
{ name: t('apiDocs.reDoc'), path: "/api-docs/redoc" },
|
{ name: t('apiDocs.reDoc'), path: `${base_url}/api-docs/redoc` },
|
||||||
{ name: t('apiDocs.openAPIExplorer'), path: "/api-docs/explorer" },
|
{ name: t('apiDocs.openAPIExplorer'), path: `${base_url}/api-docs/explorer` },
|
||||||
{ name: t('apiDocs.scalar'), path: "/api-docs/scalar" },
|
{ name: t('apiDocs.scalar'), path: `${base_url}/api-docs/scalar` },
|
||||||
{ name: t('apiDocs.downloadSpecYAML'), path: "/api-docs/spec.yaml" }
|
{ name: t('apiDocs.downloadSpecYAML'), path: `${base_url}/api-docs/spec.yaml` }
|
||||||
];
|
];
|
||||||
const handleCardClick = (path: string) => {
|
const handleCardClick = (path: string) => {
|
||||||
// Open in new tab
|
// Open in new tab
|
||||||
@@ -41,7 +43,6 @@ export default function APIDocs() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<FixedHeader />
|
<FixedHeader />
|
||||||
<Main>
|
<Main>
|
||||||
<div className='mb-2 flex items-center justify-between space-y-2 flex-wrap gap-x-4'>
|
<div className='mb-2 flex items-center justify-between space-y-2 flex-wrap gap-x-4'>
|
||||||
|
|||||||
@@ -121,9 +121,12 @@ const queryClient = new QueryClient({
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const basepath = (window as any).__BICHON_BASE__ || '/';
|
||||||
|
console.log('Current Basepath:', basepath);
|
||||||
// Create a new router instance
|
// Create a new router instance
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
routeTree,
|
routeTree,
|
||||||
|
basepath,
|
||||||
context: { queryClient },
|
context: { queryClient },
|
||||||
defaultPreload: 'intent',
|
defaultPreload: 'intent',
|
||||||
defaultPreloadStaleTime: 0,
|
defaultPreloadStaleTime: 0,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
|
|||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
base: '',
|
||||||
plugins: [react(), TanStackRouterVite()],
|
plugins: [react(), TanStackRouterVite()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
|||||||
Reference in New Issue
Block a user