Skip to content

Commit aa04ca4

Browse files
committed
Add category index on homepage
1 parent 63dbc35 commit aa04ca4

File tree

10 files changed

+289
-70
lines changed

10 files changed

+289
-70
lines changed

src/database/category.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ pub enum CategoryError {
4545
#[snafu(display("Database error"))]
4646
DB { source: sea_orm::DbErr },
4747
#[snafu(display("The category (ID: {id}) does not exist"))]
48-
NotFound { id: i32 },
48+
IDNotFound { id: i32 },
49+
#[snafu(display("The category (Name: {name}) does not exist"))]
50+
NameNotFound { name: String },
4951
#[snafu(display("Failed to save the operation log"))]
5052
Logger { source: LoggerError },
5153
}
@@ -71,6 +73,20 @@ impl CategoryOperator {
7173
.context(DBSnafu)
7274
}
7375

76+
/// Find one category by Name
77+
pub async fn find_by_name(&self, name: String) -> Result<Model, CategoryError> {
78+
let category = Entity::find()
79+
.filter(Column::Name.contains(name.clone()))
80+
.one(&self.state.database)
81+
.await
82+
.context(DBSnafu)?;
83+
84+
match category {
85+
Some(category) => Ok(category),
86+
None => Err(CategoryError::NameNotFound { name }),
87+
}
88+
}
89+
7490
/// Delete a category
7591
pub async fn delete(&self, id: i32, user: Option<User>) -> Result<String, CategoryError> {
7692
let db = &self.state.database;
@@ -101,7 +117,7 @@ impl CategoryOperator {
101117

102118
Ok(category_clone.name)
103119
}
104-
None => Err(CategoryError::NotFound { id }),
120+
None => Err(CategoryError::IDNotFound { id }),
105121
}
106122
}
107123

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ pub fn router(state: state::AppState) -> Router {
2020
Router::new()
2121
// Register dynamic routes
2222
.route("/", get(routes::index::index))
23+
.route("/upload", get(routes::index::upload))
2324
.route("/progress/{view_request}", get(routes::progress::progress))
2425
.route("/categories", get(routes::category::index))
2526
.route("/categories", post(routes::category::create))
2627
.route("/categories/new", get(routes::category::new))
2728
.route("/categories/{id}/delete", get(routes::category::delete))
29+
.route("/folders/{category_id}", get(routes::category::show))
2830
.route("/logs", get(routes::logs::index))
2931
// Register static assets routes
3032
.nest("/assets", static_router())

src/routes/category.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,33 @@ pub async fn index(
144144
},
145145
))
146146
}
147+
148+
#[derive(Template, WebTemplate)]
149+
#[template(path = "categories/show.html")]
150+
pub struct CategoryShowTemplate {
151+
/// Global application state
152+
pub state: AppStateContext,
153+
/// Logged-in user.
154+
pub user: Option<User>,
155+
/// Category
156+
category: category::Model,
157+
}
158+
159+
pub async fn show(
160+
State(app_state): State<AppState>,
161+
user: Option<User>,
162+
Path(category_name): Path<String>,
163+
) -> Result<CategoryShowTemplate, AppStateError> {
164+
let app_state_context = app_state.context().await?;
165+
166+
let category: category::Model = CategoryOperator::new(app_state.clone(), user.clone())
167+
.find_by_name(category_name.to_string())
168+
.await
169+
.context(CategorySnafu)?;
170+
171+
Ok(CategoryShowTemplate {
172+
category,
173+
state: app_state_context,
174+
user,
175+
})
176+
}

src/routes/index.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,24 @@ use axum::extract::State;
44
use snafu::prelude::*;
55

66
// TUTORIAL: https://github.com/SeaQL/sea-orm/blob/master/examples/axum_example/
7-
use crate::database::category::CategoryOperator;
7+
use crate::database::category::{self, CategoryOperator};
88
use crate::extractors::user::User;
99
use crate::state::{AppState, AppStateContext, error::*};
1010

1111
#[derive(Template, WebTemplate)]
1212
#[template(path = "index.html")]
1313
pub struct IndexTemplate {
14+
/// Global application state (errors/warnings)
15+
pub state: AppStateContext,
16+
/// Logged-in user.
17+
pub user: Option<User>,
18+
/// Categories
19+
pub categories: Vec<category::Model>,
20+
}
21+
22+
#[derive(Template, WebTemplate)]
23+
#[template(path = "upload.html")]
24+
pub struct UploadTemplate {
1425
/// Global application state (errors/warnings)
1526
pub state: AppStateContext,
1627
/// Logged-in user.
@@ -20,6 +31,23 @@ pub struct IndexTemplate {
2031
}
2132

2233
impl IndexTemplate {
34+
pub async fn new(app_state: AppState, user: Option<User>) -> Result<Self, AppStateError> {
35+
let app_state_context = app_state.context().await?;
36+
37+
let categories = CategoryOperator::new(app_state.clone(), user.clone())
38+
.list()
39+
.await
40+
.context(CategorySnafu)?;
41+
42+
Ok(IndexTemplate {
43+
state: app_state_context,
44+
user,
45+
categories,
46+
})
47+
}
48+
}
49+
50+
impl UploadTemplate {
2351
pub async fn new(app_state: AppState, user: Option<User>) -> Result<Self, AppStateError> {
2452
let categories: Vec<String> = CategoryOperator::new(app_state.clone(), user.clone())
2553
.list()
@@ -29,7 +57,7 @@ impl IndexTemplate {
2957
.map(|x| x.name)
3058
.collect();
3159

32-
Ok(IndexTemplate {
60+
Ok(UploadTemplate {
3361
state: app_state.context().await?,
3462
user,
3563
categories,
@@ -43,3 +71,10 @@ pub async fn index(
4371
) -> Result<IndexTemplate, AppStateError> {
4472
IndexTemplate::new(app_state, user).await
4573
}
74+
75+
pub async fn upload(
76+
State(app_state): State<AppState>,
77+
user: Option<User>,
78+
) -> Result<UploadTemplate, AppStateError> {
79+
UploadTemplate::new(app_state, user).await
80+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div class="dropdown">
2+
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
3+
Actions
4+
</button>
5+
<ul class="dropdown-menu">
6+
<li><a class="dropdown-item" href="/categories/new">Create category</a></li>
7+
</ul>
8+
</div>

templates/categories/show.html

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{% extends "layouts/file_system_base.html" %}
2+
3+
{% block breadcrumb %}
4+
<li class="breadcrumb-item">
5+
<a href="/">
6+
Categories
7+
</a>
8+
</li>
9+
10+
<li class="breadcrumb-item">
11+
<a href="/folders/{{ category.name }}">
12+
{{ category.name }}
13+
</a>
14+
</li>
15+
{% endblock %}
16+
17+
{% block folder_title %}
18+
{{ category.name }}
19+
{% endblock%}
20+
21+
{% block additional_buttons %}
22+
<a class="btn btn-dark" href="/">
23+
Go up
24+
</a>
25+
{% endblock %}
26+
27+
{% block system_list %}
28+
{% endblock %}

templates/index.html

Lines changed: 37 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,43 @@
1-
{% extends "base.html" %}
2-
3-
{% block main %}
4-
<div class="container">
5-
<h1>Download files</h1>
6-
7-
{% if state.free_space.free_space_percent < 5 %}
8-
<div class="alert alert-warning mt-4">
9-
The disks are almost full : <span class="fw-bold">{{ state.free_space.free_space_gib }} GiB left</span>
10-
</div>
11-
{% endif %}
1+
{% extends "layouts/file_system_base.html" %}
2+
3+
{% block breadcrumb %}
4+
<li class="breadcrumb-item">
5+
<a href="/">
6+
Categories
7+
</a>
8+
</li>
9+
{% endblock %}
1210

13-
<form method="POST" action="/upload" enctype="multipart/form-data" accept-charset="utf-8">
14-
<div class="card mt-4">
15-
<div class="card-body">
16-
<div class="form-group">
17-
<label for="collection" class="form-label mb-0">Category</label>
18-
<div id="collection" class="form-text mb-1">Choose the type of content you want to download.</div>
19-
<select class="form-select" aria-label="Choose the type of content you want to download" name="collection">{#{% set post_tag = post.tag %} TODO #}
20-
<option disabled {#{% if post_tag is not defined %}selected{% endif %}#}>Genre</option>
21-
{% for tag in categories %}
22-
<option {#{% if post_tag == tag %}selected {% endif %}#}value="{{ tag }}">{{ tag }}</option>
23-
{% endfor %}
24-
</select>
11+
{% block folder_title %}
12+
All categories
13+
{% endblock%}
14+
15+
{% block actions_buttons %}
16+
{% include "categories/dropdown_actions.html" %}
17+
{% endblock actions_buttons %}
18+
19+
{% block system_list %}
20+
{% for category in categories %}
21+
<li class="list-group-item py-3">
22+
<a class="d-block text-decoration-none" href="/folders/{{ category.name }}">
23+
<div class="row">
24+
<div class="col-9">
25+
<div class="d-flex align-items-center">
26+
<i class="fa fa-folder text-info me-3"></i>
27+
<h5 class="mb-0">
28+
{{ category.name }} <code class="ms-2"span><small>{{ category.path }}</small></code>
29+
</h5>
30+
</div>
2531
</div>
26-
</div>
27-
</div>
28-
29-
<div class="row mt-4">
30-
<div class="col-sm">
31-
{% include "sources/magnet.html" %}
32-
</div>
33-
34-
<div class="col-md-1 mt-3 mt-sm-0">
35-
<div class="d-flex align-items-center h-100 justify-content-center">
36-
<h2>OR</h2>
32+
<div class="col-3">
33+
<p class="mb-0 fst-italic text-end">
34+
<i class="fa fa-chevron-right"></i>
35+
</p>
3736
</div>
3837
</div>
38+
</a>
39+
</li>
40+
{% endfor %}
41+
{% endblock %}
3942

40-
<div class="col-sm mt-3 mt-sm-0">
41-
{% include "sources/torrent.html" %}
42-
</div>
43-
</div>
44-
45-
<div class="text-center mt-4">
46-
<input type="Submit" class="btn btn-success btn-lg" value="Next">
47-
</div>
48-
</form>
49-
50-
{% if categories.len() == 0 %}
51-
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="false">
52-
<div class="modal-dialog modal-dialog-centered">
53-
<div class="modal-content">
54-
<div class="modal-header">
55-
<h1 class="modal-title fs-5" id="staticBackdropLabel">Oops, you don't have any categories yet</h1>
56-
</div>
57-
<div class="modal-body">
58-
{% include "categories/form.html" %}
59-
</div>
60-
</div>
61-
</div>
62-
</div>
6343

64-
<script>
65-
window.addEventListener("load", (event) => {
66-
const modal = new bootstrap.Modal('#staticBackdrop').show()
67-
});
68-
</script>
69-
{% endif %}
70-
</div>
71-
{% endblock %}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{% extends "base.html" %}
2+
3+
{% block main %}
4+
<div class="container">
5+
<h1>File System</h1>
6+
7+
{% block alert_message %}{% endblock alert_message %}
8+
9+
{% if state.free_space.free_space_percent < 5 %}
10+
<div class="alert alert-warning mt-4">
11+
The disks are almost full : <span class="fw-bold">{{ state.free_space.free_space_gib }} GiB left</span>
12+
</div>
13+
{% endif %}
14+
15+
<div class="row align-items-center">
16+
<div class="col-md-10">
17+
<nav aria-label="breadcrumb">
18+
<ol class="breadcrumb mb-0">
19+
{% block breadcrumb %}{% endblock breadcrumb %}
20+
</ol>
21+
</nav>
22+
</div>
23+
24+
<div class="col-md-2 text-end">
25+
{% block actions_buttons %}{% endblock actions_buttons %}
26+
</div>
27+
</div>
28+
29+
<div class="card mt-4">
30+
<div class="card-body">
31+
<div class="p-4">
32+
<div class="d-flex align-items-center mb-4">
33+
<h4 class="mb-0">{% block folder_title %}{% endblock folder_title %}</h4> <div class="ms-4">{% block additional_buttons %}{% endblock additional_buttons %}</div>
34+
</div>
35+
36+
<ul class="list-group">
37+
{% block system_list %}{% endblock system_list %}
38+
</ul>
39+
</div>
40+
</div>
41+
</div>
42+
</div>
43+
44+
<div class="modal fade" id="createSubFolder" tabindex="-1" aria-labelledby="createSubFolderLabel" aria-hidden="false">
45+
<div class="modal-dialog">
46+
<div class="modal-content">
47+
<div class="modal-header">
48+
<h1 class="modal-title fs-5" id="staticBackdropLabel">Create sub-folder</h1>
49+
</div>
50+
<div class="modal-body">
51+
{% block content_folder_form %}{% endblock content_folder_form %}
52+
</div>
53+
</div>
54+
</div>
55+
</div>
56+
57+
{% endblock %}

templates/menus/header.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
<!-- </li> -->
3434
</ul>
3535
<span class="navbar-text">
36-
<a class="btn btn-success text-white" href="/">
36+
<a class="btn btn-success text-white" href="/upload">
3737
<i class="fa fa-download me-2"></i>
3838
Download new torrent
3939
</a>

0 commit comments

Comments
 (0)