fix(routes): serve pages with clean URLs (no .html extension)
Add server-side routes for /profile, /admin, and /shared that serve their respective HTML pages directly (same pattern already used for /login). Updated all frontend references to use clean URLs instead of .html extensions. Fixes #99
This commit is contained in:
@@ -14,8 +14,11 @@ pub fn create_web_routes() -> Router<AppState> {
|
|||||||
let static_path = config.static_path.clone();
|
let static_path = config.static_path.clone();
|
||||||
|
|
||||||
Router::new()
|
Router::new()
|
||||||
// Add specific route for login
|
// Add specific routes for clean URLs (without .html)
|
||||||
.route("/login", get(serve_login_page))
|
.route("/login", get(serve_login_page))
|
||||||
|
.route("/profile", get(serve_profile_page))
|
||||||
|
.route("/admin", get(serve_admin_page))
|
||||||
|
.route("/shared", get(serve_shared_page))
|
||||||
// Serve static files
|
// Serve static files
|
||||||
.fallback_service(
|
.fallback_service(
|
||||||
ServeDir::new(static_path)
|
ServeDir::new(static_path)
|
||||||
@@ -26,3 +29,18 @@ pub fn create_web_routes() -> Router<AppState> {
|
|||||||
async fn serve_login_page() -> Html<&'static str> {
|
async fn serve_login_page() -> Html<&'static str> {
|
||||||
Html(include_str!("../../../static/login.html"))
|
Html(include_str!("../../../static/login.html"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serve the profile page
|
||||||
|
async fn serve_profile_page() -> Html<&'static str> {
|
||||||
|
Html(include_str!("../../../static/profile.html"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serve the admin page
|
||||||
|
async fn serve_admin_page() -> Html<&'static str> {
|
||||||
|
Html(include_str!("../../../static/admin.html"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serve the shared page
|
||||||
|
async fn serve_shared_page() -> Html<&'static str> {
|
||||||
|
Html(include_str!("../../../static/shared.html"))
|
||||||
|
}
|
||||||
+1
-1
@@ -219,7 +219,7 @@ details[open] summary{margin-bottom:14px;color:#ff5e3a}
|
|||||||
<div class="access-icon"><i class="fas fa-lock"></i></div>
|
<div class="access-icon"><i class="fas fa-lock"></i></div>
|
||||||
<h2>Access Denied</h2>
|
<h2>Access Denied</h2>
|
||||||
<p>Administrator privileges required to access this panel.</p>
|
<p>Administrator privileges required to access this panel.</p>
|
||||||
<a href="/login.html"><i class="fas fa-sign-in-alt"></i> Sign in</a>
|
<a href="/login"><i class="fas fa-sign-in-alt"></i> Sign in</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="main-content" style="display:none">
|
<div id="main-content" style="display:none">
|
||||||
|
|||||||
+6
-6
@@ -207,7 +207,7 @@ function setupUserMenu() {
|
|||||||
if (adminBtn) {
|
if (adminBtn) {
|
||||||
adminBtn.addEventListener('click', () => {
|
adminBtn.addEventListener('click', () => {
|
||||||
wrapper.classList.remove('open');
|
wrapper.classList.remove('open');
|
||||||
window.location.href = '/admin.html';
|
window.location.href = '/admin';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +215,7 @@ function setupUserMenu() {
|
|||||||
if (profileBtn) {
|
if (profileBtn) {
|
||||||
profileBtn.addEventListener('click', () => {
|
profileBtn.addEventListener('click', () => {
|
||||||
wrapper.classList.remove('open');
|
wrapper.classList.remove('open');
|
||||||
window.location.href = '/profile.html';
|
window.location.href = '/profile';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1627,7 +1627,7 @@ async function checkAuthentication() {
|
|||||||
if (!exchangeResponse.ok) {
|
if (!exchangeResponse.ok) {
|
||||||
const errText = await exchangeResponse.text();
|
const errText = await exchangeResponse.text();
|
||||||
console.error('OIDC token exchange failed:', exchangeResponse.status, errText);
|
console.error('OIDC token exchange failed:', exchangeResponse.status, errText);
|
||||||
window.location.href = '/login.html?source=oidc_error';
|
window.location.href = '/login?source=oidc_error';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1677,7 +1677,7 @@ async function checkAuthentication() {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('OIDC exchange error:', err);
|
console.error('OIDC exchange error:', err);
|
||||||
window.location.href = '/login.html?source=oidc_error';
|
window.location.href = '/login?source=oidc_error';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1688,7 +1688,7 @@ async function checkAuthentication() {
|
|||||||
if (!token) {
|
if (!token) {
|
||||||
console.log('No token found, redirecting to login');
|
console.log('No token found, redirecting to login');
|
||||||
// Avoid potential loop by adding a parameter
|
// Avoid potential loop by adding a parameter
|
||||||
const redirectUrl = '/login.html?source=app';
|
const redirectUrl = '/login?source=app';
|
||||||
window.location.href = redirectUrl;
|
window.location.href = redirectUrl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1931,7 +1931,7 @@ function logout() {
|
|||||||
sessionStorage.removeItem('redirect_count');
|
sessionStorage.removeItem('redirect_count');
|
||||||
|
|
||||||
// Redirect to login page with correct path
|
// Redirect to login page with correct path
|
||||||
window.location.href = '/login.html';
|
window.location.href = '/login';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+3
-3
@@ -1189,14 +1189,14 @@ function redirectToMainApp() {
|
|||||||
// Ultimate fallback - clear everything and go to a special error page
|
// Ultimate fallback - clear everything and go to a special error page
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
window.location.href = '/login.html?critical=redirect_error';
|
window.location.href = '/login?critical=redirect_error';
|
||||||
}
|
}
|
||||||
}, 50);
|
}, 50);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Fatal error in redirectToMainApp:', error);
|
console.error('Fatal error in redirectToMainApp:', error);
|
||||||
// Emergency fallback
|
// Emergency fallback
|
||||||
try {
|
try {
|
||||||
window.location.href = '/login.html?error=redirect_fatal';
|
window.location.href = '/login?error=redirect_fatal';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Nothing more we can do
|
// Nothing more we can do
|
||||||
alert('Critical redirect error. Please reload the page and try again.');
|
alert('Critical redirect error. Please reload the page and try again.');
|
||||||
@@ -1215,5 +1215,5 @@ function logout() {
|
|||||||
localStorage.removeItem(REFRESH_TOKEN_KEY);
|
localStorage.removeItem(REFRESH_TOKEN_KEY);
|
||||||
localStorage.removeItem(TOKEN_EXPIRY_KEY);
|
localStorage.removeItem(TOKEN_EXPIRY_KEY);
|
||||||
localStorage.removeItem(USER_DATA_KEY);
|
localStorage.removeItem(USER_DATA_KEY);
|
||||||
window.location.href = '/login.html';
|
window.location.href = '/login';
|
||||||
}
|
}
|
||||||
+1
-1
@@ -15,7 +15,7 @@ function checkAuthentication() {
|
|||||||
|
|
||||||
if (!token || !tokenExpiry || new Date(tokenExpiry) < new Date()) {
|
if (!token || !tokenExpiry || new Date(tokenExpiry) < new Date()) {
|
||||||
// No token or expired token
|
// No token or expired token
|
||||||
window.location.href = '/login.html';
|
window.location.href = '/login';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -143,7 +143,7 @@ body{background:#f5f7fa;color:#1e293b;min-height:100vh;display:flex;flex-directi
|
|||||||
<div class="err-icon"><i class="fas fa-lock"></i></div>
|
<div class="err-icon"><i class="fas fa-lock"></i></div>
|
||||||
<h2>Not Authenticated</h2>
|
<h2>Not Authenticated</h2>
|
||||||
<p>Please sign in to view your profile.</p>
|
<p>Please sign in to view your profile.</p>
|
||||||
<a href="/login.html"><i class="fas fa-sign-in-alt"></i> Sign in</a>
|
<a href="/login"><i class="fas fa-sign-in-alt"></i> Sign in</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="main-content" style="display:none">
|
<div id="main-content" style="display:none">
|
||||||
|
|||||||
+3
-3
@@ -25,7 +25,7 @@
|
|||||||
<i class="fas fa-folder"></i>
|
<i class="fas fa-folder"></i>
|
||||||
<span data-i18n="nav.files">Files</span>
|
<span data-i18n="nav.files">Files</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="/shared.html" class="nav-item active">
|
<a href="/shared" class="nav-item active">
|
||||||
<i class="fas fa-share-alt"></i>
|
<i class="fas fa-share-alt"></i>
|
||||||
<span data-i18n="nav.shared">Shared</span>
|
<span data-i18n="nav.shared">Shared</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -250,7 +250,7 @@
|
|||||||
(function() {
|
(function() {
|
||||||
const token = localStorage.getItem('oxicloud_token');
|
const token = localStorage.getItem('oxicloud_token');
|
||||||
if (!token) {
|
if (!token) {
|
||||||
window.location.href = '/auth/login.html';
|
window.location.href = '/login';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Set user avatar initials
|
// Set user avatar initials
|
||||||
@@ -281,7 +281,7 @@
|
|||||||
logoutBtn.addEventListener('click', () => {
|
logoutBtn.addEventListener('click', () => {
|
||||||
localStorage.removeItem('oxicloud_token');
|
localStorage.removeItem('oxicloud_token');
|
||||||
localStorage.removeItem('oxicloud_user');
|
localStorage.removeItem('oxicloud_user');
|
||||||
window.location.href = '/auth/login.html';
|
window.location.href = '/login';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user