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:
Dionisio
2026-02-13 22:44:20 +01:00
parent 6f3baabbb2
commit 4560a8042c
7 changed files with 34 additions and 16 deletions
+19 -1
View File
@@ -14,8 +14,11 @@ pub fn create_web_routes() -> Router<AppState> {
let static_path = config.static_path.clone();
Router::new()
// Add specific route for login
// Add specific routes for clean URLs (without .html)
.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
.fallback_service(
ServeDir::new(static_path)
@@ -26,3 +29,18 @@ pub fn create_web_routes() -> Router<AppState> {
async fn serve_login_page() -> Html<&'static str> {
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
View File
@@ -219,7 +219,7 @@ details[open] summary{margin-bottom:14px;color:#ff5e3a}
<div class="access-icon"><i class="fas fa-lock"></i></div>
<h2>Access Denied</h2>
<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 id="main-content" style="display:none">
+6 -6
View File
@@ -207,7 +207,7 @@ function setupUserMenu() {
if (adminBtn) {
adminBtn.addEventListener('click', () => {
wrapper.classList.remove('open');
window.location.href = '/admin.html';
window.location.href = '/admin';
});
}
@@ -215,7 +215,7 @@ function setupUserMenu() {
if (profileBtn) {
profileBtn.addEventListener('click', () => {
wrapper.classList.remove('open');
window.location.href = '/profile.html';
window.location.href = '/profile';
});
}
@@ -1627,7 +1627,7 @@ async function checkAuthentication() {
if (!exchangeResponse.ok) {
const errText = await exchangeResponse.text();
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;
}
@@ -1677,7 +1677,7 @@ async function checkAuthentication() {
}
} catch (err) {
console.error('OIDC exchange error:', err);
window.location.href = '/login.html?source=oidc_error';
window.location.href = '/login?source=oidc_error';
return;
}
}
@@ -1688,7 +1688,7 @@ async function checkAuthentication() {
if (!token) {
console.log('No token found, redirecting to login');
// Avoid potential loop by adding a parameter
const redirectUrl = '/login.html?source=app';
const redirectUrl = '/login?source=app';
window.location.href = redirectUrl;
return;
}
@@ -1931,7 +1931,7 @@ function logout() {
sessionStorage.removeItem('redirect_count');
// Redirect to login page with correct path
window.location.href = '/login.html';
window.location.href = '/login';
}
/**
+3 -3
View File
@@ -1189,14 +1189,14 @@ function redirectToMainApp() {
// Ultimate fallback - clear everything and go to a special error page
localStorage.clear();
sessionStorage.clear();
window.location.href = '/login.html?critical=redirect_error';
window.location.href = '/login?critical=redirect_error';
}
}, 50);
} catch (error) {
console.error('Fatal error in redirectToMainApp:', error);
// Emergency fallback
try {
window.location.href = '/login.html?error=redirect_fatal';
window.location.href = '/login?error=redirect_fatal';
} catch (e) {
// Nothing more we can do
alert('Critical redirect error. Please reload the page and try again.');
@@ -1215,5 +1215,5 @@ function logout() {
localStorage.removeItem(REFRESH_TOKEN_KEY);
localStorage.removeItem(TOKEN_EXPIRY_KEY);
localStorage.removeItem(USER_DATA_KEY);
window.location.href = '/login.html';
window.location.href = '/login';
}
+1 -1
View File
@@ -15,7 +15,7 @@ function checkAuthentication() {
if (!token || !tokenExpiry || new Date(tokenExpiry) < new Date()) {
// No token or expired token
window.location.href = '/login.html';
window.location.href = '/login';
return;
}
+1 -1
View File
@@ -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>
<h2>Not Authenticated</h2>
<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 id="main-content" style="display:none">
+3 -3
View File
@@ -25,7 +25,7 @@
<i class="fas fa-folder"></i>
<span data-i18n="nav.files">Files</span>
</a>
<a href="/shared.html" class="nav-item active">
<a href="/shared" class="nav-item active">
<i class="fas fa-share-alt"></i>
<span data-i18n="nav.shared">Shared</span>
</a>
@@ -250,7 +250,7 @@
(function() {
const token = localStorage.getItem('oxicloud_token');
if (!token) {
window.location.href = '/auth/login.html';
window.location.href = '/login';
return;
}
// Set user avatar initials
@@ -281,7 +281,7 @@
logoutBtn.addEventListener('click', () => {
localStorage.removeItem('oxicloud_token');
localStorage.removeItem('oxicloud_user');
window.location.href = '/auth/login.html';
window.location.href = '/login';
});
}
})();