Skip to content

Commit

Permalink
#39 Added search functionallity to backend, testing and debug are needed
Browse files Browse the repository at this point in the history
  • Loading branch information
Dominux committed Jan 3, 2025
1 parent c679262 commit e53b8f9
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 20 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@

_Cloud storage system based on using Telegram as a storage so it doesn't use your server filesystem or any other paid cloud storage system underneath the hood._

**BTC**: `18mquj59AcB4y4VBevdn5HekG5y7gvPYGk`

https://github.com/Dominux/Pentaract/assets/55978340/b62305a7-cae3-4e1c-a509-38e415392dcf
**TON**: `UQDoGRgUIEDA30cko8k-icnI8S5i8QIq2jFvqswNvVUc9F2U`

**USDT TON**: `UQDoGRgUIEDA30cko8k-icnI8S5i8QIq2jFvqswNvVUc9F2U`

https://github.com/Dominux/Pentaract/assets/55978340/b62305a7-cae3-4e1c-a509-38e415392dcf

Pentaract is aimed to take as small disk space as possible. So it does not need any code interpreter/platform to run. The whole app is just several megabytes in size. It also uses Postgres as a database and we try our best to economy space by not creating unneeded fields and tables and to wisely pick proper datatypes.

Expand Down
46 changes: 31 additions & 15 deletions pentaract/src/repositories/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ impl<'d> FilesRepository<'d> {
WHERE storage_id = $3 AND path ~ ('^(' || regexp_quote($1) || regexp_quote($2) || '|' || regexp_quote($1) || ' \(\d+\)' || regexp_quote($2) || ')$')
ORDER BY path DESC
)
SELECT
SELECT
CASE
WHEN NOT EXISTS(
SELECT path
FROM f
SELECT path
FROM f
WHERE path = $1 || $2
) THEN $1 || $2
ELSE
Expand All @@ -118,9 +118,9 @@ impl<'d> FilesRepository<'d> {
ORDER BY i
)
SELECT $1 || ' (' || COALESCE(t.next_i, (
SELECT cte.i + 1
FROM cte
ORDER BY cte.i DESC
SELECT cte.i + 1
FROM cte
ORDER BY cte.i DESC
LIMIT 1
)) || ')' || $2
FROM cte
Expand Down Expand Up @@ -206,14 +206,14 @@ impl<'d> FilesRepository<'d> {

format!(
"
SELECT
DISTINCT {split_part} AS name,
SELECT
DISTINCT {split_part} AS name,
$1 || {split_part} = path AS is_file,
CASE
WHEN $1 || {split_part} = path THEN size
ELSE (SELECT SUM(size) FROM {FILES_TABLE} WHERE path LIKE $1 || {split_part} || '/' || '%')::BigInt
END AS size
FROM {FILES_TABLE}
FROM {FILES_TABLE}
WHERE storage_id = $2 {path_filter} AND is_uploaded AND {split_part} <> '';
"
)
Expand Down Expand Up @@ -250,6 +250,22 @@ impl<'d> FilesRepository<'d> {
Ok(fs_layer)
}

pub async fn search(
&self,
search_path: &str,
path: &str,
storage_id: Uuid,
) -> PentaractResult<Vec<File>> {
sqlx::query_as(
format!("SELECT * FROM {FILES_TABLE} WHERE storage_id = $1 AND path ILIKE $2 || '%' || $3 || '%'").as_str(),
)
.bind(storage_id)
.bind(path)
.bind(search_path)
.fetch_all(self.db)
.await
}

pub async fn get_file_by_path(&self, path: &str, storage_id: Uuid) -> PentaractResult<File> {
sqlx::query_as(
format!("SELECT * FROM {FILES_TABLE} WHERE storage_id = $1 AND path = $2").as_str(),
Expand Down Expand Up @@ -289,8 +305,8 @@ impl<'d> FilesRepository<'d> {
sqlx::query(
format!(
"
UPDATE {FILES_TABLE}
SET path = $1 || SUBSTRING(path, {chars_skip})
UPDATE {FILES_TABLE}
SET path = $1 || SUBSTRING(path, {chars_skip})
WHERE storage_id = $2 AND path LIKE $3 || '%'
"
)
Expand Down Expand Up @@ -328,7 +344,7 @@ impl<'d> FilesRepository<'d> {
// deleting file
sqlx::query(&format!(
"
DELETE FROM {FILES_TABLE}
DELETE FROM {FILES_TABLE}
WHERE storage_id = $1 AND path {where_path};
"
))
Expand All @@ -346,10 +362,10 @@ impl<'d> FilesRepository<'d> {
sqlx::query(&format!(
"
INSERT INTO {FILES_TABLE} (id, path, size, storage_id, is_uploaded)
SELECT $1, $2, 0, $3, true
WHERE
SELECT $1, $2, 0, $3, true
WHERE
NOT EXISTS (
SELECT id
SELECT id
FROM {FILES_TABLE}
WHERE storage_id = $3 AND path LIKE $2 || '%'
);
Expand Down
34 changes: 32 additions & 2 deletions pentaract/src/routers/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{collections::HashMap, path::Path, sync::Arc};

use axum::{
body::Full,
extract::{DefaultBodyLimit, Multipart, Path as RoutePath, State},
extract::{DefaultBodyLimit, Multipart, Path as RoutePath, Query, State},
http::StatusCode,
middleware,
response::{AppendHeaders, IntoResponse, Response},
Expand All @@ -20,7 +20,9 @@ use crate::{
},
errors::{PentaractError, PentaractResult},
models::files::InFile,
schemas::files::{InFileSchema, InFolderSchema, UploadParams, IN_FILE_SCHEMA_FIELDS_AMOUNT},
schemas::files::{
InFileSchema, InFolderSchema, SearchQuery, UploadParams, IN_FILE_SCHEMA_FIELDS_AMOUNT,
},
services::files::FilesService,
};

Expand All @@ -45,11 +47,22 @@ impl FilesRouter {
State(state): State<Arc<AppState>>,
Extension(user): Extension<AuthUser>,
RoutePath((storage_id, path)): RoutePath<(Uuid, String)>,
query: Query<SearchQuery>,
) -> impl IntoResponse {
let (root_path, path) = path.split_once("/").unwrap_or((&path, ""));
match root_path {
"tree" => Self::tree(state, user, storage_id, path).await,
"download" => Self::download(state, user, storage_id, path).await,
"search" => {
if let Some(search_path) = query.0.search_path {
Self::search(state, user, storage_id, path, &search_path).await
} else {
Err((
StatusCode::UNPROCESSABLE_ENTITY,
"search_path query parameter is required".to_owned(),
))
}
}
_ => Err((StatusCode::NOT_FOUND, "Not found".to_owned())),
}
}
Expand Down Expand Up @@ -203,6 +216,23 @@ impl FilesRouter {
.map_err(|e| <(StatusCode, String)>::from(e))
}

///
/// Need path with trailing slash
///
async fn search(
state: Arc<AppState>,
user: AuthUser,
storage_id: Uuid,
path: &str,
search_path: &str,
) -> Result<Response, (StatusCode, String)> {
FilesService::new(&state.db, state.tx.clone())
.search(path, storage_id, search_path, &user)
.await
.map(|files| files.into_iter().map(|file| file.into()).into_response()(headers, body))
.map_err(|e| <(StatusCode, String)>::from(e))
}

async fn delete(
State(state): State<Arc<AppState>>,
Extension(user): Extension<AuthUser>,
Expand Down
26 changes: 24 additions & 2 deletions pentaract/src/schemas/files.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use axum::body::Bytes;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::common::types::Position;
use crate::{common::types::Position, models::files::File};

#[derive(Deserialize)]
pub struct UploadParams {
Expand All @@ -29,6 +29,23 @@ impl InFileSchema {
}
}

#[derive(Serialize)]
pub struct SearchFileSchema {
pub id: Uuid,
pub path: String,
pub size: i64,
}

impl From<File> for SearchFileSchema {
fn from(value: File) -> Self {
Self {
id: value.id,
path: value.path,
size: value.size,
}
}
}

pub const IN_FILE_SCHEMA_FIELDS_AMOUNT: usize = 2;

pub struct InFolderSchema {
Expand Down Expand Up @@ -57,3 +74,8 @@ impl DownloadedChunkSchema {
Self { position, data }
}
}

#[derive(Deserialize)]
pub struct SearchQuery {
pub search_path: Option<String>,
}
12 changes: 12 additions & 0 deletions pentaract/src/services/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,18 @@ impl<'d> FilesService<'d> {
self.repo.list_dir(storage_id, path).await
}

pub async fn search(
self,
storage_id: Uuid,
path: &str,
search_path: &str,
user: &AuthUser,
) -> PentaractResult<Vec<File>> {
check_access(&self.access_repo, user.id, storage_id, &AccessType::R).await?;

self.repo.search(search_path, path, storage_id).await
}

pub async fn rename(
&self,
old_path: &str,
Expand Down

0 comments on commit e53b8f9

Please sign in to comment.