fix: schema init, duplicate routes, and image preview bugs
- Move pg_trgm extension creation before CalDAV indexes that depend on it - Remove duplicate app-password route registration that caused panic - Fix missing comma in language selector array (Dutch entry) - Await async canEdit() in file click handler (Promise was always truthy) - Detect images by extension fallback when mime_type is octet-stream (files uploaded via Nextcloud WebDAV API lack correct mime types) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+3
-4
@@ -6,6 +6,9 @@
|
||||
-- All tables use IF NOT EXISTS for idempotent re-runs.
|
||||
-- ============================================================
|
||||
|
||||
-- ── Extensions required by indexes below ──
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
|
||||
-- ============================================================
|
||||
-- 1. AUTH SCHEMA
|
||||
-- ============================================================
|
||||
@@ -287,10 +290,6 @@ COMMENT ON TABLE caldav.calendar_events IS 'Calendar events (VEVENT) stored with
|
||||
COMMENT ON TABLE caldav.calendar_shares IS 'Calendar sharing permissions between users';
|
||||
COMMENT ON TABLE caldav.calendar_properties IS 'Custom WebDAV properties on calendars';
|
||||
|
||||
-- ── pg_trgm extension for GIN trigram indexes (ILIKE / LIKE substring search) ──
|
||||
-- Required before creating any gin_trgm_ops indexes below.
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
|
||||
-- ============================================================
|
||||
-- 3. CARDDAV SCHEMA (RFC 6352)
|
||||
-- ============================================================
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ services:
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
|
||||
oxicloud:
|
||||
image: oxicloud
|
||||
restart: always
|
||||
|
||||
@@ -238,7 +238,7 @@ impl Default for DatabaseConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
// Updated connection string with default credentials that PostgreSQL often uses
|
||||
connection_string: "postgres://postgres:postgres@localhost:5439/oxicloud".to_string(),
|
||||
connection_string: "postgres://postgres:postgres@localhost:5432/oxicloud".to_string(),
|
||||
max_connections: 20,
|
||||
min_connections: 5,
|
||||
connect_timeout_secs: 10,
|
||||
|
||||
-12
@@ -185,7 +185,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
auth_protected_routes, auth_public_routes, login_route, refresh_route, register_route,
|
||||
setup_route,
|
||||
};
|
||||
use oxicloud::interfaces::api::handlers::app_password_handler;
|
||||
use oxicloud::interfaces::api::handlers::device_auth_handler;
|
||||
use oxicloud::interfaces::middleware::auth::auth_middleware;
|
||||
use oxicloud::interfaces::middleware::csrf::csrf_middleware;
|
||||
@@ -270,15 +269,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
))
|
||||
.with_state(app_state.clone());
|
||||
|
||||
// App Password management endpoints (protected — require JWT)
|
||||
let app_password_protected = app_password_handler::app_password_routes()
|
||||
.layer(axum::middleware::from_fn(csrf_middleware))
|
||||
.layer(axum::middleware::from_fn_with_state(
|
||||
app_state.clone(),
|
||||
auth_middleware,
|
||||
))
|
||||
.with_state(app_state.clone());
|
||||
|
||||
// Protected API routes — require valid JWT token
|
||||
let protected_api = api_routes
|
||||
.layer(axum::middleware::from_fn(csrf_middleware))
|
||||
@@ -316,8 +306,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.nest("/api/auth/device", device_public)
|
||||
// Device Auth Grant protected endpoints (verify + device management)
|
||||
.nest("/api/auth/device", device_protected)
|
||||
// App Password management endpoints (create, list, revoke)
|
||||
.nest("/api/auth", app_password_protected)
|
||||
// Public API routes (share access, i18n) — no auth required
|
||||
.nest("/api", public_api_routes)
|
||||
// All other API routes are protected by auth middleware
|
||||
|
||||
+4
-2
@@ -754,12 +754,14 @@ const ui = {
|
||||
}
|
||||
// WOPI editor intercept: open Office documents in the WOPI editor
|
||||
// But NOT image files - those should be previewed in the inline viewer
|
||||
const isImage = file.mime_type && file.mime_type.startsWith('image/');
|
||||
const ext = (file.name || '').split('.').pop().toLowerCase();
|
||||
const imageExts = ['jpg','jpeg','png','gif','svg','webp','bmp','ico','heic','heif','avif','tiff'];
|
||||
const isImage = (file.mime_type && file.mime_type.startsWith('image/')) || imageExts.includes(ext);
|
||||
if (!isImage && window.wopiEditor && await window.wopiEditor.canEdit(file.name)) {
|
||||
window.wopiEditor.openInModal(file.id, file.name, 'edit');
|
||||
return;
|
||||
}
|
||||
if (self.isViewableFile(file)) {
|
||||
if (self.isViewableFile(file) || isImage) {
|
||||
if (window.inlineViewer) window.inlineViewer.openFile(file);
|
||||
else window.fileOps.downloadFile(file.id, file.name);
|
||||
} else {
|
||||
|
||||
@@ -17,7 +17,7 @@ function getAvailableLanguages() {
|
||||
{ code: 'fr', name: 'Français', flag: '🇫🇷' },
|
||||
{ code: 'de', name: 'Deutsch', flag: '🇩🇪' },
|
||||
{ code: 'pt', name: 'Português', flag: '🇧🇷' },
|
||||
{ code: 'it', name: 'Italiano', flag: '🇮🇹' }
|
||||
{ code: 'it', name: 'Italiano', flag: '🇮🇹' },
|
||||
{ code: 'nl', name: 'Nederlands', flag: '🇳🇱' }
|
||||
];
|
||||
}
|
||||
|
||||
@@ -93,30 +93,33 @@ class InlineViewer {
|
||||
|
||||
// WOPI editor intercept: open Office documents in the WOPI editor
|
||||
// But NOT image files - those should be previewed in the inline viewer
|
||||
const isImage = file.mime_type && file.mime_type.startsWith('image/');
|
||||
// Detect images by mime type OR extension (uploads via WebDAV may lack correct mime)
|
||||
const ext = (file.name || '').split('.').pop().toLowerCase();
|
||||
const imageExts = ['jpg','jpeg','png','gif','svg','webp','bmp','ico','heic','heif','avif','tiff'];
|
||||
const isImage = (file.mime_type && file.mime_type.startsWith('image/')) || imageExts.includes(ext);
|
||||
if (!isImage && window.wopiEditor && await window.wopiEditor.canEdit(file.name)) {
|
||||
window.wopiEditor.openInModal(file.id, file.name, 'edit');
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentFile = file;
|
||||
|
||||
|
||||
// Get container
|
||||
const modal = document.getElementById('inline-viewer-modal');
|
||||
const container = modal.querySelector('.inline-viewer-container');
|
||||
const title = modal.querySelector('.inline-viewer-title');
|
||||
|
||||
|
||||
// Clear container
|
||||
container.innerHTML = '';
|
||||
|
||||
|
||||
// Set title
|
||||
title.textContent = file.name;
|
||||
|
||||
|
||||
// Set controls visibility
|
||||
const controls = modal.querySelector('.inline-viewer-controls');
|
||||
|
||||
|
||||
// Show viewer based on file type
|
||||
if (file.mime_type && file.mime_type.startsWith('image/')) {
|
||||
if (isImage) {
|
||||
// Show zoom controls
|
||||
controls.style.display = 'flex';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user