mirror of
https://github.com/DioCrafts/OxiCloud.git
synced 2025-10-05 16:12:49 +02:00
fix several bugs
This commit is contained in:
121
Cargo.lock
generated
121
Cargo.lock
generated
@@ -356,9 +356,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.17"
|
||||
version = "1.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
|
||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
@@ -501,9 +501,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
@@ -580,9 +580,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
@@ -613,9 +613,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
@@ -1027,9 +1027,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
|
||||
checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -1037,6 +1037,7 @@ dependencies = [
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"hyper",
|
||||
"libc",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
@@ -1046,9 +1047,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.62"
|
||||
version = "0.1.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127"
|
||||
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
@@ -1209,9 +1210,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
@@ -1307,9 +1308,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
@@ -1415,9 +1416,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.5"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
@@ -1594,9 +1595,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.71"
|
||||
version = "0.10.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd"
|
||||
checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
@@ -1625,13 +1626,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.106"
|
||||
name = "openssl-src"
|
||||
version = "300.5.0+3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
|
||||
checksum = "e8ce546f549326b0e6052b649198487d91320875da901e7bd11a06d1ee3f9c2f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"openssl-src",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
@@ -1662,6 +1673,7 @@ dependencies = [
|
||||
"jsonwebtoken",
|
||||
"mime_guess",
|
||||
"mockall",
|
||||
"openssl",
|
||||
"pin-project-lite",
|
||||
"quick-xml",
|
||||
"rand",
|
||||
@@ -1925,9 +1937,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.10"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
|
||||
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@@ -2063,9 +2075,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.3"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96"
|
||||
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
@@ -2342,9 +2354,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
@@ -2803,9 +2815,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.44.1"
|
||||
version = "1.44.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
|
||||
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -3278,11 +3290,37 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
version = "0.61.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3298,7 +3336,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-strings 0.3.1",
|
||||
"windows-targets 0.53.0",
|
||||
]
|
||||
|
||||
@@ -3320,6 +3358,15 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
@@ -3691,9 +3738,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "2.5.0"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27c03817464f64e23f6f37574b4fdc8cf65925b5bfd2b0f2aedf959791941f88"
|
||||
checksum = "1dcb24d0152526ae49b9b96c1dcf71850ca1e0b882e4e28ed898a93c41334744"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"arbitrary",
|
||||
|
11
Cargo.toml
11
Cargo.toml
@@ -5,16 +5,16 @@ edition = "2021"
|
||||
|
||||
|
||||
[dependencies]
|
||||
axum = { version = "0.8.1", features = ["multipart", "http1", "tokio", "macros"] }
|
||||
tokio = { version = "1.44.1", features = ["full"] }
|
||||
axum = { version = "0.8.3", features = ["multipart", "http1", "tokio", "macros"] }
|
||||
tokio = { version = "1.44.2", features = ["full"] }
|
||||
tokio-util = { version = "0.7.14", features = ["io", "codec"] }
|
||||
tokio-stream = { version = "0.1.17", features = ["fs"] }
|
||||
bytes = "1.10.1"
|
||||
tempfile = "3.19.1"
|
||||
tower = "0.5.2"
|
||||
tower-http = { version = "0.6.2", features = ["fs", "compression-gzip", "trace", "cors", "add-extension", "request-id"] }
|
||||
flate2 = "1.1.0"
|
||||
zip = "2.5.0"
|
||||
flate2 = "1.1.1"
|
||||
zip = "2.6.1"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
|
||||
chrono = { version = "0.4.40", features = ["serde"] }
|
||||
@@ -39,9 +39,10 @@ rand_core = { version = "0.6.4", features = ["std"] }
|
||||
time = "0.3.41"
|
||||
axum-server = "0.6.0"
|
||||
hyper = { version = "1.6.0", features = ["full"] }
|
||||
url = "2.5.0"
|
||||
url = "2.5.4"
|
||||
quick-xml = "0.30.0"
|
||||
http-body-util = "0.1.3"
|
||||
openssl = { version = "0.10.72", features = ["vendored"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
@@ -2,7 +2,7 @@
|
||||
FROM rust:1.85-alpine AS cacher
|
||||
WORKDIR /app
|
||||
RUN apk --no-cache upgrade && \
|
||||
apk add --no-cache musl-dev openssl-dev pkgconfig postgresql-dev
|
||||
apk add --no-cache musl-dev pkgconfig postgresql-dev gcc perl make
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
# Create a minimal project to download and cache dependencies
|
||||
RUN mkdir -p src && \
|
||||
@@ -14,7 +14,7 @@ RUN mkdir -p src && \
|
||||
FROM rust:1.85-alpine AS builder
|
||||
WORKDIR /app
|
||||
RUN apk --no-cache upgrade && \
|
||||
apk add --no-cache musl-dev openssl-dev pkgconfig postgresql-dev
|
||||
apk add --no-cache musl-dev pkgconfig postgresql-dev gcc perl make
|
||||
# Copy cached dependencies
|
||||
COPY --from=cacher /app/target target
|
||||
COPY --from=cacher /usr/local/cargo /usr/local/cargo
|
||||
@@ -30,7 +30,7 @@ RUN cargo build --release
|
||||
FROM alpine:3.21.3
|
||||
# Install only necessary runtime dependencies and update packages
|
||||
RUN apk --no-cache upgrade && \
|
||||
apk add --no-cache libgcc openssl ca-certificates libpq tzdata
|
||||
apk add --no-cache libgcc ca-certificates libpq tzdata
|
||||
|
||||
# Copy only the compiled binary
|
||||
COPY --from=builder /app/target/release/oxicloud /usr/local/bin/
|
||||
|
89
ISSUE_45_SOLUTION.md
Normal file
89
ISSUE_45_SOLUTION.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Solución para el issue #45: [BUG] Admin already exists?
|
||||
|
||||
## Descripción del problema
|
||||
|
||||
Al intentar configurar un usuario administrador, algunos usuarios reciben el error:
|
||||
|
||||
```
|
||||
2025-04-09T14:01:26.733566Z ERROR oxicloud::interfaces::api::handlers::auth_handler: Registration failed for user admin: Already Exists: El usuario 'admin' ya existe
|
||||
```
|
||||
|
||||
## Causa raíz
|
||||
|
||||
Este problema ocurre debido a cómo está implementada la migración de datos inicial. En el archivo `migrations/20250408000001_default_users.sql`, el sistema intenta crear un usuario admin por defecto durante la migración inicial, pero:
|
||||
|
||||
1. Si luego el usuario intenta crear manualmente otro usuario con nombre "admin", el sistema detecta el conflicto.
|
||||
2. La cláusula `ON CONFLICT (id) DO NOTHING` solo previene conflictos en el ID, no en el nombre de usuario.
|
||||
|
||||
## Solución implementada
|
||||
|
||||
Hemos realizado los siguientes cambios:
|
||||
|
||||
1. Modificado `migrations/20250408000001_default_users.sql` para comprobar primero si el usuario "admin" ya existe:
|
||||
|
||||
```sql
|
||||
-- Check if admin user already exists before creating it
|
||||
DO $$$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM auth.users WHERE username = 'admin') THEN
|
||||
-- Create admin user (password: Admin123!)
|
||||
INSERT INTO auth.users (
|
||||
id,
|
||||
username,
|
||||
...
|
||||
) VALUES (...);
|
||||
END IF;
|
||||
END;
|
||||
$$$;
|
||||
```
|
||||
|
||||
2. Creado un script `scripts/reset_admin.sql` que puede ejecutarse para eliminar el usuario admin existente:
|
||||
|
||||
```sql
|
||||
-- Set the correct schema
|
||||
SET search_path TO auth;
|
||||
|
||||
-- Delete the admin user if it exists
|
||||
DELETE FROM auth.users WHERE username = 'admin';
|
||||
|
||||
-- Output remaining users for verification
|
||||
SELECT username, email, role FROM auth.users ORDER BY role, username;
|
||||
```
|
||||
|
||||
3. Actualizado la documentación en `doc/DATABASE-MIGRATIONS.md` con instrucciones detalladas para resolver este problema.
|
||||
|
||||
## Instrucciones para usuarios afectados
|
||||
|
||||
Si encuentras el error "Admin already exists", tienes dos opciones:
|
||||
|
||||
### Opción 1: Usar el script proporcionado
|
||||
```bash
|
||||
cat scripts/reset_admin.sql | docker exec -i oxicloud-postgres-1 psql -U postgres -d oxicloud
|
||||
```
|
||||
|
||||
### Opción 2: Hacerlo manualmente
|
||||
1. Conéctate al contenedor de PostgreSQL:
|
||||
```bash
|
||||
# Encuentra el contenedor
|
||||
docker ps
|
||||
# Ejemplo: oxicloud-postgres-1
|
||||
docker exec -it oxicloud-postgres-1 bash
|
||||
```
|
||||
|
||||
2. Conéctate a la base de datos:
|
||||
```bash
|
||||
psql -U postgres -d oxicloud
|
||||
```
|
||||
|
||||
3. Borra el usuario admin existente:
|
||||
```sql
|
||||
SET search_path TO auth;
|
||||
DELETE FROM auth.users WHERE username = 'admin';
|
||||
```
|
||||
|
||||
4. Verifica que se eliminó correctamente:
|
||||
```sql
|
||||
SELECT username, email, role FROM auth.users;
|
||||
```
|
||||
|
||||
5. Sal y registra un nuevo usuario admin a través de la interfaz web.
|
14
TODO-LIST.md
14
TODO-LIST.md
@@ -104,6 +104,8 @@ This document contains the task list for the development of OxiCloud, a minimali
|
||||
- [ ] Add support for locking
|
||||
- [ ] Test compatibility with standard clients
|
||||
- [ ] Optimize WebDAV performance
|
||||
- [ ] Implement Range Requests (RFC 7233) for resumable transfers
|
||||
- [ ] Support partial file updates with HTTP PATCH for bandwidth efficiency
|
||||
|
||||
### Sync Client
|
||||
- [ ] Design client architecture in Rust
|
||||
@@ -112,6 +114,9 @@ This document contains the task list for the development of OxiCloud, a minimali
|
||||
- [ ] Implement conflict detection
|
||||
- [ ] Add configuration options
|
||||
- [ ] Create minimal client version for Windows/macOS/Linux
|
||||
- [ ] Implement bandwidth throttling controls
|
||||
- [ ] Add delta synchronization for large files
|
||||
- [ ] Support synchronization pausing and resuming
|
||||
|
||||
## Phase 5: Advanced Features
|
||||
|
||||
@@ -146,6 +151,9 @@ This document contains the task list for the development of OxiCloud, a minimali
|
||||
- [x] Implement asynchronous processing for heavy tasks
|
||||
- [ ] Optimize database queries
|
||||
- [ ] Implement scaling strategies
|
||||
- [ ] Implement transfer acceleration with multipart chunking
|
||||
- [ ] Implement differential sync algorithm (similar to rsync)
|
||||
- [ ] Add strong ETag support for more efficient caching
|
||||
|
||||
### Frontend
|
||||
- [ ] Optimize initial asset loading
|
||||
@@ -154,6 +162,9 @@ This document contains the task list for the development of OxiCloud, a minimali
|
||||
- [ ] Optimize UI rendering
|
||||
- [ ] Implement intelligent prefetching
|
||||
- [ ] Add basic offline support
|
||||
- [ ] Implement client-side image resizing before upload
|
||||
- [ ] Add HTTP/2 support for multiplexing requests
|
||||
- [ ] Implement progressive image loading
|
||||
|
||||
### Storage
|
||||
- [ ] Research deduplication options
|
||||
@@ -162,6 +173,9 @@ This document contains the task list for the development of OxiCloud, a minimali
|
||||
- [ ] Implement log rotation and archiving
|
||||
- [ ] Create automated backup system
|
||||
- [ ] Add support for distributed storage
|
||||
- [ ] Implement media transcoding for optimized delivery
|
||||
- [ ] Add content-aware compression by file format
|
||||
- [ ] Implement dynamic thumbnail resizing based on viewport
|
||||
|
||||
## Infrastructure and Deployment
|
||||
|
||||
|
@@ -136,6 +136,45 @@ match migration_check {
|
||||
|
||||
3. **Permisos insuficientes**: Asegúrate de que el usuario de la base de datos tenga permisos suficientes para crear esquemas, tablas e índices.
|
||||
|
||||
4. **Error "Admin already exists"**: Si al intentar registrar un usuario admin recibes el error "El usuario 'admin' ya existe", sigue estos pasos:
|
||||
|
||||
a. Conéctate al contenedor de PostgreSQL:
|
||||
```bash
|
||||
# Encuentra el contenedor
|
||||
docker ps
|
||||
# Ejemplo: oxicloud-postgres-1
|
||||
docker exec -it oxicloud-postgres-1 bash
|
||||
```
|
||||
|
||||
b. Conéctate a la base de datos:
|
||||
```bash
|
||||
psql -U postgres -d oxicloud
|
||||
```
|
||||
|
||||
c. Establece el esquema y borra el usuario admin existente:
|
||||
```sql
|
||||
SET search_path TO auth;
|
||||
DELETE FROM auth.users WHERE username = 'admin';
|
||||
```
|
||||
|
||||
d. Verifica la eliminación:
|
||||
```sql
|
||||
SELECT username, email, role FROM auth.users;
|
||||
```
|
||||
|
||||
e. Sal de PostgreSQL:
|
||||
```sql
|
||||
\q
|
||||
exit
|
||||
```
|
||||
|
||||
f. Ahora puedes registrar un nuevo usuario admin a través de la interfaz de OxiCloud.
|
||||
|
||||
Alternativamente, utiliza el script proporcionado:
|
||||
```bash
|
||||
cat scripts/reset_admin.sql | docker exec -i oxicloud-postgres-1 psql -U postgres -d oxicloud
|
||||
```
|
||||
|
||||
## Beneficios del Enfoque Basado en Migraciones
|
||||
|
||||
- **Separación de Responsabilidades**: Las migraciones están separadas del código de la aplicación.
|
||||
|
@@ -1,35 +1,49 @@
|
||||
-- Migration 002: Default Users
|
||||
|
||||
-- Create admin user (password: Admin123!)
|
||||
INSERT INTO auth.users (
|
||||
id,
|
||||
username,
|
||||
email,
|
||||
password_hash,
|
||||
role,
|
||||
storage_quota_bytes
|
||||
) VALUES (
|
||||
'00000000-0000-0000-0000-000000000000',
|
||||
'admin',
|
||||
'admin@oxicloud.local',
|
||||
'$argon2id$v=19$m=65536,t=3,p=4$c2FsdHNhbHRzYWx0c2FsdA$H3VxE8LL2qPT31DM3loTg6D+O4MSc2sD7GjlQ5h7Jkw', -- Admin123!
|
||||
'admin',
|
||||
107374182400 -- 100GB for admin
|
||||
) ON CONFLICT (id) DO NOTHING;
|
||||
-- Check if admin user already exists before creating it
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM auth.users WHERE username = 'admin') THEN
|
||||
-- Create admin user (password: Admin123!)
|
||||
INSERT INTO auth.users (
|
||||
id,
|
||||
username,
|
||||
email,
|
||||
password_hash,
|
||||
role,
|
||||
storage_quota_bytes
|
||||
) VALUES (
|
||||
'00000000-0000-0000-0000-000000000000',
|
||||
'admin',
|
||||
'admin@oxicloud.local',
|
||||
'$argon2id$v=19$m=65536,t=3,p=4$c2FsdHNhbHRzYWx0c2FsdA$H3VxE8LL2qPT31DM3loTg6D+O4MSc2sD7GjlQ5h7Jkw', -- Admin123!
|
||||
'admin',
|
||||
107374182400 -- 100GB for admin
|
||||
);
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- Create test user (password: test123)
|
||||
INSERT INTO auth.users (
|
||||
id,
|
||||
username,
|
||||
email,
|
||||
password_hash,
|
||||
role,
|
||||
storage_quota_bytes
|
||||
) VALUES (
|
||||
'11111111-1111-1111-1111-111111111111',
|
||||
'test',
|
||||
'test@oxicloud.local',
|
||||
'$argon2id$v=19$m=65536,t=3,p=4$c2FsdHNhbHRzYWx0c2FsdA$ZG17Z7SFKhs9zWYbuk08CkHpyiznnZapYnxN5Vi62R4', -- test123
|
||||
'user',
|
||||
10737418240 -- 10GB for test user
|
||||
) ON CONFLICT (id) DO NOTHING;
|
||||
-- Check if test user already exists before creating it
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM auth.users WHERE username = 'test') THEN
|
||||
-- Create test user (password: test123)
|
||||
INSERT INTO auth.users (
|
||||
id,
|
||||
username,
|
||||
email,
|
||||
password_hash,
|
||||
role,
|
||||
storage_quota_bytes
|
||||
) VALUES (
|
||||
'11111111-1111-1111-1111-111111111111',
|
||||
'test',
|
||||
'test@oxicloud.local',
|
||||
'$argon2id$v=19$m=65536,t=3,p=4$c2FsdHNhbHRzYWx0c2FsdA$ZG17Z7SFKhs9zWYbuk08CkHpyiznnZapYnxN5Vi62R4', -- test123
|
||||
'user',
|
||||
10737418240 -- 10GB for test user
|
||||
);
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
19
scripts/reset_admin.sql
Normal file
19
scripts/reset_admin.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
-- Script to safely reset the admin user in OxiCloud
|
||||
-- Run this script to delete the existing admin user if you're having issues creating one
|
||||
|
||||
-- Set the correct schema
|
||||
SET search_path TO auth;
|
||||
|
||||
-- Delete the admin user if it exists
|
||||
DELETE FROM auth.users WHERE username = 'admin';
|
||||
|
||||
-- Check if the user was deleted
|
||||
SELECT 'Admin user has been removed successfully. You can now create a new admin user.' AS message
|
||||
WHERE NOT EXISTS (SELECT 1 FROM auth.users WHERE username = 'admin');
|
||||
|
||||
-- Check if there are still users in the system
|
||||
SELECT 'Warning: No users remain in the system. You should register a new admin user.' AS warning
|
||||
WHERE NOT EXISTS (SELECT 1 FROM auth.users LIMIT 1);
|
||||
|
||||
-- Output remaining users for verification
|
||||
SELECT username, email, role FROM auth.users ORDER BY role, username;
|
@@ -210,7 +210,7 @@ impl WebDavAdapter {
|
||||
files: &[FileDto],
|
||||
subfolders: &[FolderDto],
|
||||
request: &PropFindRequest,
|
||||
depth: &str,
|
||||
_depth: &str,
|
||||
base_href: &str,
|
||||
) -> Result<()> {
|
||||
let mut xml_writer = Writer::new(writer);
|
||||
@@ -226,7 +226,7 @@ impl WebDavAdapter {
|
||||
}
|
||||
|
||||
// If depth allows, add responses for files and subfolders
|
||||
if depth != "0" {
|
||||
if _depth != "0" {
|
||||
// Add responses for files
|
||||
for file in files {
|
||||
Self::write_file_response(&mut xml_writer, file, request, &format!("{}{}", base_href, file.name))?;
|
||||
@@ -249,7 +249,7 @@ impl WebDavAdapter {
|
||||
writer: W,
|
||||
file: &FileDto,
|
||||
request: &PropFindRequest,
|
||||
depth: &str,
|
||||
_depth: &str,
|
||||
href: &str,
|
||||
) -> Result<()> {
|
||||
let mut xml_writer = Writer::new(writer);
|
||||
|
@@ -38,7 +38,7 @@ impl FavoritesUseCase for FavoritesService {
|
||||
item_type as "item_type",
|
||||
created_at as "created_at"
|
||||
FROM auth.user_favorites
|
||||
WHERE user_id = $1
|
||||
WHERE user_id = $1::TEXT
|
||||
ORDER BY created_at DESC
|
||||
"#
|
||||
)
|
||||
@@ -90,7 +90,7 @@ impl FavoritesUseCase for FavoritesService {
|
||||
sqlx::query(
|
||||
r#"
|
||||
INSERT INTO auth.user_favorites (user_id, item_id, item_type)
|
||||
VALUES ($1, $2, $3)
|
||||
VALUES ($1::TEXT, $2, $3)
|
||||
ON CONFLICT (user_id, item_id, item_type) DO NOTHING
|
||||
"#
|
||||
)
|
||||
@@ -123,7 +123,7 @@ impl FavoritesUseCase for FavoritesService {
|
||||
let result = sqlx::query(
|
||||
r#"
|
||||
DELETE FROM auth.user_favorites
|
||||
WHERE user_id = $1 AND item_id = $2 AND item_type = $3
|
||||
WHERE user_id = $1::TEXT AND item_id = $2 AND item_type = $3
|
||||
"#
|
||||
)
|
||||
.bind(user_uuid)
|
||||
@@ -164,7 +164,7 @@ impl FavoritesUseCase for FavoritesService {
|
||||
r#"
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM auth.user_favorites
|
||||
WHERE user_id = $1 AND item_id = $2 AND item_type = $3
|
||||
WHERE user_id = $1::TEXT AND item_id = $2 AND item_type = $3
|
||||
) AS "is_favorite"
|
||||
"#
|
||||
)
|
||||
|
@@ -45,7 +45,7 @@ impl RecentItemsUseCase for RecentService {
|
||||
item_type as "item_type",
|
||||
accessed_at as "accessed_at"
|
||||
FROM auth.user_recent_files
|
||||
WHERE user_id = $1
|
||||
WHERE user_id = $1::TEXT
|
||||
ORDER BY accessed_at DESC
|
||||
LIMIT $2
|
||||
"#
|
||||
@@ -99,7 +99,7 @@ impl RecentItemsUseCase for RecentService {
|
||||
sqlx::query(
|
||||
r#"
|
||||
INSERT INTO auth.user_recent_files (user_id, item_id, item_type, accessed_at)
|
||||
VALUES ($1, $2, $3, CURRENT_TIMESTAMP)
|
||||
VALUES ($1::TEXT, $2, $3, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (user_id, item_id, item_type)
|
||||
DO UPDATE SET accessed_at = CURRENT_TIMESTAMP
|
||||
"#
|
||||
@@ -136,7 +136,7 @@ impl RecentItemsUseCase for RecentService {
|
||||
let result = sqlx::query(
|
||||
r#"
|
||||
DELETE FROM auth.user_recent_files
|
||||
WHERE user_id = $1 AND item_id = $2 AND item_type = $3
|
||||
WHERE user_id = $1::TEXT AND item_id = $2 AND item_type = $3
|
||||
"#
|
||||
)
|
||||
.bind(user_uuid)
|
||||
@@ -176,7 +176,7 @@ impl RecentItemsUseCase for RecentService {
|
||||
sqlx::query(
|
||||
r#"
|
||||
DELETE FROM auth.user_recent_files
|
||||
WHERE user_id = $1
|
||||
WHERE user_id = $1::TEXT
|
||||
"#
|
||||
)
|
||||
.bind(user_uuid)
|
||||
@@ -208,7 +208,7 @@ impl RecentService {
|
||||
DELETE FROM auth.user_recent_files
|
||||
WHERE id IN (
|
||||
SELECT id FROM auth.user_recent_files
|
||||
WHERE user_id = $1
|
||||
WHERE user_id = $1::TEXT
|
||||
ORDER BY accessed_at DESC
|
||||
OFFSET $2
|
||||
)
|
||||
|
@@ -19,7 +19,7 @@ use crate::domain::repositories::file_repository::{
|
||||
FileRepository, FileRepositoryError, FileRepositoryResult
|
||||
};
|
||||
use crate::application::services::storage_mediator::StorageMediator;
|
||||
use crate::application::ports::outbound::IdMappingPort;
|
||||
// use crate::application::ports::outbound::IdMappingPort;
|
||||
use crate::infrastructure::services::id_mapping_service::IdMappingError;
|
||||
use crate::infrastructure::services::file_metadata_cache::{FileMetadataCache, CacheEntryType};
|
||||
use crate::domain::services::path_service::{StoragePath, PathService};
|
||||
|
@@ -4,7 +4,7 @@ use async_trait::async_trait;
|
||||
|
||||
use crate::domain::services::path_service::{PathService, StoragePath};
|
||||
use crate::application::services::storage_mediator::StorageMediator;
|
||||
use crate::application::ports::outbound::IdMappingPort;
|
||||
// use crate::application::ports::outbound::IdMappingPort;
|
||||
use crate::domain::repositories::file_repository::FileRepositoryError;
|
||||
use crate::common::errors::DomainError;
|
||||
use crate::application::ports::storage_ports::FilePathResolutionPort;
|
||||
|
@@ -11,7 +11,7 @@ use crate::domain::repositories::folder_repository::{
|
||||
FolderRepository, FolderRepositoryError, FolderRepositoryResult
|
||||
};
|
||||
use crate::domain::services::path_service::{StoragePath, PathService};
|
||||
use crate::application::ports::outbound::IdMappingPort;
|
||||
// use crate::application::ports::outbound::IdMappingPort;
|
||||
use crate::infrastructure::services::id_mapping_service::{IdMappingService, IdMappingError};
|
||||
use crate::application::services::storage_mediator::StorageMediator;
|
||||
use crate::application::ports::outbound::FolderStoragePort;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use sqlx::{PgPool, Row, Executor};
|
||||
use sqlx::{PgPool, Row};
|
||||
use std::sync::Arc;
|
||||
use chrono::Utc;
|
||||
use futures::future::BoxFuture;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use sqlx::{PgPool, Row, Executor};
|
||||
use sqlx::{PgPool, Row};
|
||||
use std::sync::Arc;
|
||||
use futures::future::BoxFuture;
|
||||
|
||||
|
@@ -8,7 +8,7 @@ use axum::{
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
use futures::Stream;
|
||||
use futures::StreamExt;
|
||||
// use futures::StreamExt;
|
||||
use std::task::{Context, Poll};
|
||||
use std::pin::Pin;
|
||||
|
||||
|
@@ -4,7 +4,7 @@ use axum::Json;
|
||||
use serde_json::json;
|
||||
use tracing::{debug, error, instrument};
|
||||
|
||||
use crate::application::ports::trash_ports::TrashUseCase;
|
||||
// use crate::application::ports::trash_ports::TrashUseCase;
|
||||
use crate::common::di::AppState;
|
||||
use crate::interfaces::middleware::auth::AuthUser;
|
||||
|
||||
|
@@ -15,7 +15,6 @@ use axum::{
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
use http_body_util::BodyExt;
|
||||
use chrono::Utc;
|
||||
use bytes::Buf;
|
||||
|
||||
@@ -28,7 +27,7 @@ use crate::common::errors::AppError;
|
||||
// Create a custom DAV header since it's not in the standard headers
|
||||
const HEADER_DAV: HeaderName = HeaderName::from_static("dav");
|
||||
const HEADER_LOCK_TOKEN: HeaderName = HeaderName::from_static("lock-token");
|
||||
const HEADER_IF: HeaderName = HeaderName::from_static("if");
|
||||
// const HEADER_IF: HeaderName = HeaderName::from_static("if");
|
||||
|
||||
/**
|
||||
* Creates and returns the WebDAV router with all required endpoints.
|
||||
@@ -81,7 +80,7 @@ async fn handle_options(
|
||||
) -> Result<Response<Body>, AppError> {
|
||||
// Extract State and Path from request
|
||||
let parts = req.uri().path().split('/').collect::<Vec<&str>>();
|
||||
let path = if parts.len() > 2 {
|
||||
let _path = if parts.len() > 2 {
|
||||
parts[2..].join("/")
|
||||
} else {
|
||||
"".to_string()
|
||||
@@ -313,10 +312,10 @@ async fn handle_proppatch(
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let state = req.extensions().get::<Arc<AppState>>().ok_or_else(|| {
|
||||
let _state = req.extensions().get::<Arc<AppState>>().ok_or_else(|| {
|
||||
AppError::internal_error("Missing AppState extension")
|
||||
})?;
|
||||
let user = req.extensions().get::<CurrentUser>().ok_or_else(|| {
|
||||
let _user = req.extensions().get::<CurrentUser>().ok_or_else(|| {
|
||||
AppError::unauthorized("Authentication required")
|
||||
})?;
|
||||
|
||||
@@ -391,7 +390,7 @@ async fn handle_get(
|
||||
let state = req.extensions().get::<Arc<AppState>>().ok_or_else(|| {
|
||||
AppError::internal_error("Missing AppState extension")
|
||||
})?;
|
||||
let user = req.extensions().get::<CurrentUser>().ok_or_else(|| {
|
||||
let _user = req.extensions().get::<CurrentUser>().ok_or_else(|| {
|
||||
AppError::unauthorized("Authentication required")
|
||||
})?;
|
||||
|
||||
@@ -405,7 +404,7 @@ async fn handle_get(
|
||||
}
|
||||
|
||||
// Get file metadata
|
||||
let file = file_service.get_file_by_path(&path).await.map_err(|e| {
|
||||
let file = file_service.get_file_by_path(&path).await.map_err(|_e| {
|
||||
AppError::not_found(format!("File not found: {}", path))
|
||||
})?;
|
||||
|
||||
@@ -654,7 +653,7 @@ async fn handle_delete(
|
||||
let state = req.extensions().get::<Arc<AppState>>().ok_or_else(|| {
|
||||
AppError::internal_error("Missing AppState extension")
|
||||
})?;
|
||||
let user = req.extensions().get::<CurrentUser>().ok_or_else(|| {
|
||||
let _user = req.extensions().get::<CurrentUser>().ok_or_else(|| {
|
||||
AppError::unauthorized("Authentication required")
|
||||
})?;
|
||||
|
||||
@@ -677,7 +676,7 @@ async fn handle_delete(
|
||||
})?;
|
||||
} else {
|
||||
// Try to delete file
|
||||
let file = file_service.get_file_by_path(&path).await.map_err(|e| {
|
||||
let file = file_service.get_file_by_path(&path).await.map_err(|_e| {
|
||||
AppError::not_found(format!("Resource not found: {}", path))
|
||||
})?;
|
||||
|
||||
@@ -718,7 +717,7 @@ async fn handle_move(
|
||||
let state = req.extensions().get::<Arc<AppState>>().ok_or_else(|| {
|
||||
AppError::internal_error("Missing AppState extension")
|
||||
})?;
|
||||
let user = req.extensions().get::<CurrentUser>().ok_or_else(|| {
|
||||
let _user = req.extensions().get::<CurrentUser>().ok_or_else(|| {
|
||||
AppError::unauthorized("Authentication required")
|
||||
})?;
|
||||
|
||||
@@ -779,7 +778,7 @@ async fn handle_move(
|
||||
}
|
||||
} else {
|
||||
// Try to move file
|
||||
let file = file_service.get_file_by_path(&source_path).await.map_err(|e| {
|
||||
let file = file_service.get_file_by_path(&source_path).await.map_err(|_e| {
|
||||
AppError::not_found(format!("Resource not found: {}", source_path))
|
||||
})?;
|
||||
|
||||
@@ -826,7 +825,7 @@ async fn handle_copy(
|
||||
let state = req.extensions().get::<Arc<AppState>>().ok_or_else(|| {
|
||||
AppError::internal_error("Missing AppState extension")
|
||||
})?;
|
||||
let user = req.extensions().get::<CurrentUser>().ok_or_else(|| {
|
||||
let _user = req.extensions().get::<CurrentUser>().ok_or_else(|| {
|
||||
AppError::unauthorized("Authentication required")
|
||||
})?;
|
||||
|
||||
@@ -884,7 +883,7 @@ async fn handle_copy(
|
||||
}
|
||||
};
|
||||
|
||||
let new_folder = folder_service.create_folder(create_dto).await.map_err(|e| {
|
||||
let _new_folder = folder_service.create_folder(create_dto).await.map_err(|e| {
|
||||
AppError::internal_error(format!("Failed to create destination folder: {}", e))
|
||||
})?;
|
||||
|
||||
@@ -908,7 +907,7 @@ async fn handle_copy(
|
||||
}
|
||||
} else {
|
||||
// Try to copy file
|
||||
let file = file_service.get_file_by_path(&source_path).await.map_err(|e| {
|
||||
let file = file_service.get_file_by_path(&source_path).await.map_err(|_e| {
|
||||
AppError::not_found(format!("Resource not found: {}", source_path))
|
||||
})?;
|
||||
|
||||
@@ -964,7 +963,7 @@ async fn handle_lock(
|
||||
};
|
||||
|
||||
// Get the state and user in a way that doesn't keep req borrowed
|
||||
let state = {
|
||||
let _state = {
|
||||
let state_ref = req.extensions().get::<Arc<AppState>>().ok_or_else(|| {
|
||||
AppError::internal_error("Missing AppState extension")
|
||||
})?;
|
||||
@@ -1104,7 +1103,7 @@ async fn handle_unlock(
|
||||
) -> Result<Response<Body>, AppError> {
|
||||
// Clone all necessary data first to avoid borrow issues
|
||||
let uri = req.uri().clone();
|
||||
let path = {
|
||||
let _path = {
|
||||
let parts = uri.path().split('/').collect::<Vec<&str>>();
|
||||
if parts.len() > 2 {
|
||||
parts[2..].join("/")
|
||||
@@ -1135,7 +1134,7 @@ async fn handle_unlock(
|
||||
.ok_or_else(|| AppError::bad_request("Lock-Token header required"))?;
|
||||
|
||||
// Extract token from header value (format: <token>)
|
||||
let token = lock_token
|
||||
let _token = lock_token
|
||||
.trim()
|
||||
.trim_start_matches('<')
|
||||
.trim_end_matches('>')
|
||||
|
Reference in New Issue
Block a user