fix
This commit is contained in:
@@ -16,7 +16,7 @@ use crate::{
|
||||
AuthenticationChallengeResponse, PasskeyLoginFinishPayload, PasskeyLoginStartPayload,
|
||||
PasskeyRegistrationFinishPayload, PasskeySummary, RegistrationChallengeResponse,
|
||||
},
|
||||
AuthenticatedUser,
|
||||
AuthenticatedUser, TenantScopedConn,
|
||||
},
|
||||
error::{AppError, AppResult},
|
||||
http::responders::JsonResponse,
|
||||
@@ -180,7 +180,7 @@ pub async fn select_tenant(
|
||||
)]
|
||||
pub async fn logout(
|
||||
State(state): State<AppState>,
|
||||
user: AuthenticatedUser,
|
||||
TenantScopedConn { mut conn, user, .. }: TenantScopedConn,
|
||||
jar: Option<TypedHeader<Cookie>>,
|
||||
) -> AppResult<(HeaderMap, StatusCode)> {
|
||||
let refresh_cookie = jar.as_ref().and_then(|cookies| {
|
||||
@@ -188,7 +188,7 @@ pub async fn logout(
|
||||
.get(SESSION_COOKIE_NAME)
|
||||
.map(|value| value.to_owned())
|
||||
});
|
||||
AuthService::new(&state).logout(user, refresh_cookie.as_deref())
|
||||
AuthService::new(&state).logout(&mut conn, &user, refresh_cookie.as_deref())
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
||||
@@ -186,12 +186,16 @@ pub async fn get_document(
|
||||
)]
|
||||
pub async fn upload_document(
|
||||
State(state): State<AppState>,
|
||||
scoped_conn: TenantScopedConn,
|
||||
TenantScopedConn {
|
||||
mut conn,
|
||||
tenant_id,
|
||||
user_id,
|
||||
..
|
||||
}: TenantScopedConn,
|
||||
mut multipart: Multipart,
|
||||
) -> AppResult<JsonResponse<DocumentDetailResponse>> {
|
||||
let tenant_id = scoped_conn.tenant_id;
|
||||
let user_id = scoped_conn.user_id;
|
||||
drop(scoped_conn);
|
||||
let tenant_id = tenant_id;
|
||||
let user_id = user_id;
|
||||
let mut file_bytes: Option<Vec<u8>> = None;
|
||||
let mut original_name: Option<String> = None;
|
||||
let mut content_type: Option<String> = None;
|
||||
@@ -353,7 +357,10 @@ pub async fn upload_document(
|
||||
};
|
||||
|
||||
let service = DocumentsService::new(&state);
|
||||
let outcome = match service.upload_document(tenant_id, user_id, request).await {
|
||||
let outcome = match service
|
||||
.upload_document(&mut conn, tenant_id, user_id, request)
|
||||
.await
|
||||
{
|
||||
Ok(outcome) => outcome,
|
||||
Err(err) => {
|
||||
error!(error = ?err, original_name = %original_name_for_log, "document upload failed");
|
||||
@@ -470,7 +477,7 @@ pub async fn get_document_asset(
|
||||
Path(asset_id): Path<Uuid>,
|
||||
Query(query): Query<AssetObjectsQuery>,
|
||||
TenantScopedConn {
|
||||
mut conn,
|
||||
conn,
|
||||
tenant_id,
|
||||
..
|
||||
}: TenantScopedConn,
|
||||
@@ -485,7 +492,7 @@ pub async fn get_document_asset(
|
||||
}
|
||||
let service = DocumentsService::new(&state);
|
||||
let detail = service
|
||||
.get_document_asset(&mut conn, tenant_id, asset_id, start, limit)
|
||||
.get_document_asset(conn, tenant_id, asset_id, start, limit)
|
||||
.await?;
|
||||
ok_json(detail)
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ pub async fn list_folder_contents(
|
||||
)?;
|
||||
|
||||
let documents = if include_documents {
|
||||
service.hydrate_documents(&mut conn, tenant_id, user_id, documents)?
|
||||
service.hydrate_documents(&mut conn, user_id, documents)?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
@@ -23,18 +23,18 @@ use crate::schema::{
|
||||
document_versions::dsl as document_versions_dsl, documents::dsl as documents_dsl,
|
||||
folders::dsl as folders_dsl, user_memberships::dsl as memberships_dsl, users::dsl as users_dsl,
|
||||
};
|
||||
use crate::state::AppState;
|
||||
use crate::state::{AppState, PgPooledConnection};
|
||||
use crate::tenants::{apply_tenant_guc, apply_user_guc, clear_user_guc};
|
||||
use crate::utils::{error::StorageResultExt, http::inline_content_disposition, time::to_http_date};
|
||||
|
||||
const REALM: &str = "Papercrate WebDAV";
|
||||
const DOWNLOAD_URL_TTL_SECONDS: u64 = 300;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct WebDavContext {
|
||||
tenant_id: Uuid,
|
||||
_user_id: Uuid,
|
||||
_username: String,
|
||||
conn: PgPooledConnection,
|
||||
}
|
||||
|
||||
pub fn create_router() -> Router<AppState> {
|
||||
@@ -72,7 +72,7 @@ async fn handle_propfind(
|
||||
path: &str,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Response, AppError> {
|
||||
let context = match authenticate(state, &headers)? {
|
||||
let mut context = match authenticate(state, &headers)? {
|
||||
Some(user) => user,
|
||||
None => return Ok(unauthorized_response()),
|
||||
};
|
||||
@@ -87,17 +87,18 @@ async fn handle_propfind(
|
||||
let tenant_id = context.tenant_id;
|
||||
|
||||
let resources = if segments.is_empty() {
|
||||
let contents = fetch_folder_contents(state, tenant_id, None)?;
|
||||
let contents = fetch_folder_contents(&mut context.conn, tenant_id, None)?;
|
||||
build_resources_for_folder(None, &[], &contents, depth)
|
||||
} else {
|
||||
let resolution = match resolve_path(state, tenant_id, &segments)? {
|
||||
let resolution = match resolve_path(&mut context.conn, tenant_id, &segments)? {
|
||||
Some(resolved) => resolved,
|
||||
None => return Ok(not_found_response()),
|
||||
};
|
||||
|
||||
match resolution {
|
||||
ResolvedPath::Folder { folder, chain } => {
|
||||
let contents = fetch_folder_contents(state, tenant_id, Some(folder.id))?;
|
||||
let contents =
|
||||
fetch_folder_contents(&mut context.conn, tenant_id, Some(folder.id))?;
|
||||
build_resources_for_folder(Some(&folder), &chain, &contents, depth)
|
||||
}
|
||||
ResolvedPath::Document {
|
||||
@@ -128,7 +129,7 @@ async fn handle_get_or_head(
|
||||
headers: HeaderMap,
|
||||
method: Method,
|
||||
) -> Result<Response, AppError> {
|
||||
let context = match authenticate(state, &headers)? {
|
||||
let mut context = match authenticate(state, &headers)? {
|
||||
Some(user) => user,
|
||||
None => return Ok(unauthorized_response()),
|
||||
};
|
||||
@@ -139,7 +140,7 @@ async fn handle_get_or_head(
|
||||
return Ok(method_not_allowed());
|
||||
}
|
||||
|
||||
let resolution = match resolve_path(state, tenant_id, &segments)? {
|
||||
let resolution = match resolve_path(&mut context.conn, tenant_id, &segments)? {
|
||||
Some(resolved) => resolved,
|
||||
None => return Ok(not_found_response()),
|
||||
};
|
||||
@@ -233,18 +234,16 @@ fn parse_segments(path: &str) -> AppResult<Vec<String>> {
|
||||
}
|
||||
|
||||
fn fetch_folder_contents(
|
||||
state: &AppState,
|
||||
conn: &mut PgPooledConnection,
|
||||
tenant_id: Uuid,
|
||||
folder_id: Option<Uuid>,
|
||||
) -> AppResult<WebDavFolderContents> {
|
||||
let mut conn = state.db_for_tenant(tenant_id)?;
|
||||
|
||||
let folder = match folder_id {
|
||||
Some(id) => Some(
|
||||
folders_dsl::folders
|
||||
.filter(folders_dsl::tenant_id.eq(tenant_id))
|
||||
.find(id)
|
||||
.first::<Folder>(&mut conn)?,
|
||||
.first::<Folder>(conn)?,
|
||||
),
|
||||
None => None,
|
||||
};
|
||||
@@ -254,12 +253,12 @@ fn fetch_folder_contents(
|
||||
.filter(folders_dsl::tenant_id.eq(tenant_id))
|
||||
.filter(folders_dsl::parent_id.eq(Some(id)))
|
||||
.order(folders_dsl::name.asc())
|
||||
.load(&mut conn)?,
|
||||
.load(conn)?,
|
||||
None => folders_dsl::folders
|
||||
.filter(folders_dsl::tenant_id.eq(tenant_id))
|
||||
.filter(folders_dsl::parent_id.is_null())
|
||||
.order(folders_dsl::name.asc())
|
||||
.load(&mut conn)?,
|
||||
.load(conn)?,
|
||||
};
|
||||
|
||||
let mut docs_query = documents_dsl::documents
|
||||
@@ -274,7 +273,7 @@ fn fetch_folder_contents(
|
||||
|
||||
let documents: Vec<Document> = docs_query
|
||||
.order(documents_dsl::created_at.desc())
|
||||
.load(&mut conn)?;
|
||||
.load(conn)?;
|
||||
|
||||
let version_ids: Vec<Uuid> = documents.iter().map(|doc| doc.current_version_id).collect();
|
||||
let versions: Vec<DocumentVersion> = if version_ids.is_empty() {
|
||||
@@ -282,7 +281,7 @@ fn fetch_folder_contents(
|
||||
} else {
|
||||
document_versions_dsl::document_versions
|
||||
.filter(document_versions_dsl::id.eq_any(&version_ids))
|
||||
.load(&mut conn)?
|
||||
.load(conn)?
|
||||
};
|
||||
|
||||
let mut version_map = versions
|
||||
@@ -498,6 +497,7 @@ fn authenticate(state: &AppState, headers: &HeaderMap) -> Result<Option<WebDavCo
|
||||
tenant_id,
|
||||
_user_id: user.id,
|
||||
_username: user.username,
|
||||
conn,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -689,11 +689,10 @@ enum ResolvedPath {
|
||||
}
|
||||
|
||||
fn resolve_path(
|
||||
state: &AppState,
|
||||
conn: &mut PgPooledConnection,
|
||||
tenant_id: Uuid,
|
||||
segments: &[String],
|
||||
) -> AppResult<Option<ResolvedPath>> {
|
||||
let mut conn = state.db_for_tenant(tenant_id)?;
|
||||
let mut parent_id: Option<Uuid> = None;
|
||||
let mut chain: Vec<String> = Vec::new();
|
||||
let mut current_folder: Option<Folder> = None;
|
||||
@@ -701,7 +700,7 @@ fn resolve_path(
|
||||
for (index, segment) in segments.iter().enumerate() {
|
||||
let is_last = index == segments.len() - 1;
|
||||
|
||||
if let Some(folder) = find_folder_by_name(&mut conn, tenant_id, parent_id, segment)? {
|
||||
if let Some(folder) = find_folder_by_name(conn, tenant_id, parent_id, segment)? {
|
||||
chain.push(folder.name.clone());
|
||||
if is_last {
|
||||
return Ok(Some(ResolvedPath::Folder { folder, chain }));
|
||||
@@ -713,7 +712,7 @@ fn resolve_path(
|
||||
|
||||
if is_last {
|
||||
if let Some((document, version)) =
|
||||
find_document_by_filename(&mut conn, tenant_id, parent_id, segment)?
|
||||
find_document_by_filename(conn, tenant_id, parent_id, segment)?
|
||||
{
|
||||
chain.push(document.filename.clone());
|
||||
return Ok(Some(ResolvedPath::Document {
|
||||
@@ -725,7 +724,7 @@ fn resolve_path(
|
||||
}
|
||||
|
||||
if let Ok(uuid) = Uuid::parse_str(segment) {
|
||||
if let Some(folder) = find_folder_by_id(&mut conn, tenant_id, uuid)? {
|
||||
if let Some(folder) = find_folder_by_id(conn, tenant_id, uuid)? {
|
||||
if folder.parent_id != parent_id {
|
||||
return Ok(None);
|
||||
}
|
||||
@@ -738,7 +737,7 @@ fn resolve_path(
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some((document, version)) = find_document_by_id(&mut conn, tenant_id, uuid)? {
|
||||
if let Some((document, version)) = find_document_by_id(conn, tenant_id, uuid)? {
|
||||
if document.folder_id != parent_id {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user