feat(server): add working remove buttons to session page
parent
a57e301d16
commit
21b3450aeb
|
@ -1,18 +1,22 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
Extension, Router,
|
Extension, Router,
|
||||||
extract::{Query, State},
|
extract::{Path, Query, State},
|
||||||
http::HeaderMap,
|
http::HeaderMap,
|
||||||
routing::get,
|
routing::{delete, get},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
server::{Context, error::AppResult},
|
server::{
|
||||||
|
Context,
|
||||||
|
error::{AppError, AppResult},
|
||||||
|
},
|
||||||
web::{Page, TemplateExt, TemplateResponse, ToQuery, View},
|
web::{Page, TemplateExt, TemplateResponse, ToQuery, View},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn router(ctx: Context) -> Router<Context> {
|
pub fn router(ctx: Context) -> Router<Context> {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/sessions", get(get_sessions))
|
.route("/sessions", get(get_sessions))
|
||||||
|
.route("/sessions/{id}", delete(delete_session))
|
||||||
.route_layer(axum::middleware::from_fn_with_state(
|
.route_layer(axum::middleware::from_fn_with_state(
|
||||||
ctx.clone(),
|
ctx.clone(),
|
||||||
super::auth_web_middleware,
|
super::auth_web_middleware,
|
||||||
|
@ -40,3 +44,26 @@ pub async fn get_sessions(
|
||||||
.authenticated(true)
|
.authenticated(true)
|
||||||
.response(&ctx.tera))
|
.response(&ctx.tera))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn delete_session(
|
||||||
|
State(ctx): State<Context>,
|
||||||
|
Extension(user): Extension<gpodder::User>,
|
||||||
|
Path(id): Path<i64>,
|
||||||
|
) -> AppResult<()> {
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
let session = ctx.store.get_session(id)?;
|
||||||
|
|
||||||
|
// Check to ensure a user can't remove a session that's not theirs
|
||||||
|
if session.user.id != user.id {
|
||||||
|
return Err(AppError::Unauthorized);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.store.remove_session(session.id)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,11 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ session.user_agent }}</th>
|
<th>{{ session.user_agent }}</th>
|
||||||
<th>{{ session.last_seen }}</th>
|
<th>{{ session.last_seen }}</th>
|
||||||
<th>Remove</th>
|
<th>
|
||||||
|
<a hx-delete="/sessions/{{ session.id }}"
|
||||||
|
hx-target="closest tr"
|
||||||
|
>Remove</a>
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if next_page_query %}
|
{% if next_page_query %}
|
||||||
|
|
|
@ -11,6 +11,7 @@ pub enum View {
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct Session {
|
struct Session {
|
||||||
|
id: i64,
|
||||||
user_agent: Option<String>,
|
user_agent: Option<String>,
|
||||||
last_seen: DateTime<Utc>,
|
last_seen: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
@ -49,6 +50,7 @@ impl Template for View {
|
||||||
impl From<gpodder::Session> for Session {
|
impl From<gpodder::Session> for Session {
|
||||||
fn from(value: gpodder::Session) -> Self {
|
fn from(value: gpodder::Session) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
id: value.id,
|
||||||
user_agent: value.user_agent,
|
user_agent: value.user_agent,
|
||||||
last_seen: value.last_seen,
|
last_seen: value.last_seen,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue