diff --git a/server/service/src/main.rs b/server/service/src/main.rs index 51caf02..b325066 100644 --- a/server/service/src/main.rs +++ b/server/service/src/main.rs @@ -16,13 +16,13 @@ use actix_web::{middleware, web, App, HttpResponse, HttpServer}; use failure::Error; use r2d2_sqlite::SqliteConnectionManager; use rusqlite::params; -use std::{env, cmp, io, fmt}; +use std::{env, cmp, io}; use std::ops::Deref; use serde_json::Value; const DEFAULT_SIZE: usize = 25; -#[derive(Copy, Clone, Deserialize)] +#[derive(Copy, Clone, Debug, Deserialize)] enum SortKey { Name, Size, @@ -37,20 +37,7 @@ impl Default for SortKey { } } -impl fmt::Display for SortKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let s = match &self { - Self::Name => "name", - Self::Size => "size_bytes", - Self::Seeders => "seeders", - Self::Leechers => "leechers", - Self::Scraped => "scraped_date", - }; - write!(f, "{}", s) - } -} - -#[derive(Copy, Clone, Deserialize)] +#[derive(Copy, Clone, Debug, Deserialize)] enum SortDirection { Asc, Desc, @@ -62,16 +49,6 @@ impl Default for SortDirection { } } -impl fmt::Display for SortDirection { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let s = match &self { - Self::Asc => "asc", - Self::Desc => "desc", - }; - write!(f, "{}", s) - } -} - #[actix_rt::main] async fn main() -> io::Result<()> { println!("Access me at {}", endpoint()); @@ -140,6 +117,8 @@ async fn search( Ok(res) } +// TODO what is NewQuery used for? +// it is not a file search, that is done through SearchQuery #[derive(Deserialize)] struct NewQuery { page: Option, @@ -167,6 +146,29 @@ async fn new_torrents( Ok(res) } +fn build_order_clause(type_: &str, sort_key: SortKey, sort_dir: SortDirection) -> String { + let dir = match sort_dir { + SortDirection::Asc => "asc", + SortDirection::Desc => "desc", + }; + + let column = match sort_key { + SortKey::Name => { + if type_ == "file" { + "path" + } else { + "name" + } + }, + SortKey::Size => "size_bytes", + SortKey::Seeders => "seeders", + SortKey::Leechers => "leechers", + SortKey::Scraped => "scraped_date", + }; + + format!("{} {}", column, dir) +} + fn search_query( query: web::Query, conn: r2d2::PooledConnection, @@ -185,7 +187,7 @@ fn search_query( let offset = size * (page - 1); println!( - "query = {}, type = {}, page = {}, size = {}, sort_key = {}, sort_dir = {}", + "query = {}, type = {}, page = {}, size = {}, sort_key = {:?}, sort_dir = {:?}", q, type_, page, size, sort_key, sort_dir ); @@ -213,7 +215,7 @@ fn new_query( let offset = size * (page - 1); println!( - "new, type = {}, page = {}, size = {}, sort_key = {}, sort_dir = {}", + "new, type = {}, page = {}, size = {}, sort_key = {:?}, sort_dir = {:?}", type_, page, size, sort_key, sort_dir ); @@ -248,8 +250,9 @@ fn torrent_search( size: usize, offset: usize, ) -> Result, Error> { - // `sort_key` and `sort_dir` are already sanitized and should not be escaped: - let stmt_str = format!("select * from torrents where name like '%' || ?1 || '%' order by {} {} limit ?2, ?3", sort_key, sort_dir); + let order_clause = build_order_clause("torrent", sort_key, sort_dir); + // `order_clause` is already sanitized and should not be escaped: + let stmt_str = format!("select * from torrents where name like '%' || ?1 || '%' order by {} limit ?2, ?3", order_clause); let mut stmt = conn.prepare(&stmt_str)?; let torrent_iter = stmt.query_map( params![ @@ -334,8 +337,9 @@ fn torrent_file_search( size: usize, offset: usize, ) -> Result, Error> { - // `sort_key` and `sort_dir` are already sanitized and should not be escaped: - let stmt_str = format!("select * from files where path like '%' || ?1 || '%' order by {} {} limit ?2, ?3", sort_key, sort_dir); + let order_clause = build_order_clause("file", sort_key, sort_dir); + // `order_clause` is already sanitized and should not be escaped: + let stmt_str = format!("select * from files where path like '%' || ?1 || '%' order by {} limit ?2, ?3", order_clause); let mut stmt = conn.prepare(&stmt_str).unwrap(); let file_iter = stmt.query_map( params![ diff --git a/server/ui/src/components/navbar.tsx b/server/ui/src/components/navbar.tsx index a1d7cb7..9f200b0 100644 --- a/server/ui/src/components/navbar.tsx +++ b/server/ui/src/components/navbar.tsx @@ -8,7 +8,6 @@ interface State { } export class Navbar extends Component { - state: State = { searchParams: { page: 1, @@ -80,20 +79,20 @@ export class Navbar extends Component { let searchParams: SearchParams = { q: event.target.value, page: 1, - sort_key: 'Name', - sort_dir: 'Desc', + sort_key: i.state.searchParams.sort_key, + sort_dir: i.state.searchParams.sort_dir, type_: i.state.searchParams.type_ } i.setState({ searchParams: searchParams }); } + // TODO why does switching from torrent to file search clear the sort_key? searchTypeChange(i: Navbar, event) { - console.log("in searchTypeChange"); let searchParams: SearchParams = { q: i.state.searchParams.q, page: 1, - sort_key: 'Name', - sort_dir: 'Desc', + sort_key: i.state.searchParams.sort_key, + sort_dir: i.state.searchParams.sort_dir, type_: event.target.value } i.setState({ searchParams: searchParams }); diff --git a/server/ui/src/components/search.tsx b/server/ui/src/components/search.tsx index 24326cd..39c7864 100644 --- a/server/ui/src/components/search.tsx +++ b/server/ui/src/components/search.tsx @@ -11,39 +11,6 @@ interface State { searching: Boolean; } -class SortableLink extends Component { - render({ sortKey, state: { searchParams } }) { - return - - {sortKey} - {this.renderIcon(sortKey, searchParams)} - - ; - } - - buildSearchURL(key, searchParams) { - let page, direction; - if (key === searchParams.sort_key) { - page = searchParams.page; - direction = searchParams.sort_dir === "Asc" ? "Desc" : "Asc"; - } else { - page = 1; - direction = "Desc"; - } - return `/#/search/${searchParams.type_}/${searchParams.q}/${page}/${key}/${direction}`; - } - - renderIcon(sortKey, searchParams) { - if (searchParams.sort_key !== sortKey) { - return ""; - } - if (searchParams.sort_dir === "Asc") { - return ; - } - return ; - } -) - export class Search extends Component { state: State = { results: { @@ -64,6 +31,7 @@ export class Search extends Component { } componentDidMount() { + console.log("comp did mount"); this.state.searchParams = { page: Number(this.props.match.params.page), q: this.props.match.params.q, @@ -76,6 +44,7 @@ export class Search extends Component { // Re-do search if the props have changed componentDidUpdate(lastProps: any) { + console.log("comp did update"); if (lastProps.match && lastProps.match.params !== this.props.match.params) { this.state.searchParams = { page: Number(this.props.match.params.page), @@ -144,6 +113,48 @@ export class Search extends Component { ) } + sortLink(sortKey) { + return ( + + + {sortKey} + {this.sortLinkIcon(sortKey)} + + + ) + } + + buildSortURL(sortKey) { + const searchParams = this.state.searchParams; + let page, sortDir; + if (sortKey === searchParams.sort_key) { + page = searchParams.page; + sortDir = searchParams.sort_dir === "Asc" ? "Desc" : "Asc"; + } else { + page = 1; + sortDir = "Desc"; + } + return `/#/search/${searchParams.type_}/${searchParams.q}/${page}/${sortKey}/${sortDir}`; + } + + sortLinkIcon(sortKey) { + const searchParams = this.state.searchParams; + + if (searchParams.sort_key !== sortKey) { + return ""; + } + + if (searchParams.sort_dir === "Asc") { + return ( + + ) + } else { + return ( + + ) + } + } + torrentsTable() { return (
@@ -151,19 +162,19 @@ export class Search extends Component { - + {this.sortLink("Name")} - + {this.sortLink("Size")} - + {this.sortLink("Seeders")} - + {this.sortLink("Leechers")} - + {this.sortLink("Scraped")}