mirror of
https://github.com/lennart-k/rustical.git
synced 2026-01-30 12:58:28 +00:00
Some work on the frontend
This commit is contained in:
@@ -8,6 +8,7 @@ use axum::{
|
||||
};
|
||||
use headers::{ContentType, HeaderMapExt};
|
||||
use http::{Method, StatusCode};
|
||||
use routes::{addressbooks::route_addressbooks, calendars::route_calendars};
|
||||
use rustical_oidc::{OidcConfig, OidcServiceConfig, route_get_oidc_callback, route_post_oidc};
|
||||
use rustical_store::{
|
||||
AddressbookStore, CalendarStore,
|
||||
@@ -20,6 +21,7 @@ mod assets;
|
||||
mod config;
|
||||
pub mod nextcloud_login;
|
||||
mod oidc_user_store;
|
||||
pub(crate) mod pages;
|
||||
mod routes;
|
||||
|
||||
pub use config::FrontendConfig;
|
||||
@@ -56,6 +58,7 @@ pub fn frontend_router<AP: AuthenticationProvider, CS: CalendarStore, AS: Addres
|
||||
post(route_delete_app_token::<AP>),
|
||||
)
|
||||
// Calendar
|
||||
.route("/user/{user}/calendar", get(route_calendars::<CS>))
|
||||
.route(
|
||||
"/user/{user}/calendar/{calendar}",
|
||||
get(route_calendar::<CS>),
|
||||
@@ -65,6 +68,7 @@ pub fn frontend_router<AP: AuthenticationProvider, CS: CalendarStore, AS: Addres
|
||||
post(route_calendar_restore::<CS>),
|
||||
)
|
||||
// Addressbook
|
||||
.route("/user/{user}/addressbook", get(route_addressbooks::<AS>))
|
||||
.route(
|
||||
"/user/{user}/addressbook/{addressbook}",
|
||||
get(route_addressbook::<AS>),
|
||||
|
||||
1
crates/frontend/src/pages/mod.rs
Normal file
1
crates/frontend/src/pages/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod user;
|
||||
14
crates/frontend/src/pages/user.rs
Normal file
14
crates/frontend/src/pages/user.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use askama::Template;
|
||||
use askama_web::WebTemplate;
|
||||
use rustical_store::auth::Principal;
|
||||
|
||||
pub trait Section: Template {
|
||||
fn name() -> &'static str;
|
||||
}
|
||||
|
||||
#[derive(Template, WebTemplate)]
|
||||
#[template(path = "pages/user.html")]
|
||||
pub struct UserPage<S: Section> {
|
||||
pub user: Principal,
|
||||
pub section: S,
|
||||
}
|
||||
53
crates/frontend/src/routes/addressbooks.rs
Normal file
53
crates/frontend/src/routes/addressbooks.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use askama::Template;
|
||||
use askama_web::WebTemplate;
|
||||
use axum::{Extension, extract::Path, response::IntoResponse};
|
||||
use http::StatusCode;
|
||||
use rustical_store::{Addressbook, AddressbookStore, auth::Principal};
|
||||
|
||||
use crate::pages::user::{Section, UserPage};
|
||||
|
||||
impl Section for AddressbooksSection {
|
||||
fn name() -> &'static str {
|
||||
"addressbooks"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Template, WebTemplate)]
|
||||
#[template(path = "components/sections/addressbooks_section.html")]
|
||||
pub struct AddressbooksSection {
|
||||
pub user: Principal,
|
||||
pub addressbooks: Vec<Addressbook>,
|
||||
pub deleted_addressbooks: Vec<Addressbook>,
|
||||
}
|
||||
|
||||
pub async fn route_addressbooks<AS: AddressbookStore>(
|
||||
Path(user_id): Path<String>,
|
||||
Extension(addr_store): Extension<Arc<AS>>,
|
||||
user: Principal,
|
||||
) -> impl IntoResponse {
|
||||
if user_id != user.id {
|
||||
return StatusCode::UNAUTHORIZED.into_response();
|
||||
}
|
||||
|
||||
let mut addressbooks = vec![];
|
||||
for group in user.memberships() {
|
||||
addressbooks.extend(addr_store.get_addressbooks(group).await.unwrap());
|
||||
}
|
||||
|
||||
let mut deleted_addressbooks = vec![];
|
||||
for group in user.memberships() {
|
||||
deleted_addressbooks.extend(addr_store.get_deleted_addressbooks(group).await.unwrap());
|
||||
}
|
||||
|
||||
UserPage {
|
||||
section: AddressbooksSection {
|
||||
user: user.clone(),
|
||||
addressbooks,
|
||||
deleted_addressbooks,
|
||||
},
|
||||
user,
|
||||
}
|
||||
.into_response()
|
||||
}
|
||||
52
crates/frontend/src/routes/calendars.rs
Normal file
52
crates/frontend/src/routes/calendars.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::pages::user::{Section, UserPage};
|
||||
use askama::Template;
|
||||
use askama_web::WebTemplate;
|
||||
use axum::{Extension, extract::Path, response::IntoResponse};
|
||||
use http::StatusCode;
|
||||
use rustical_store::{Calendar, CalendarStore, auth::Principal};
|
||||
|
||||
impl Section for CalendarsSection {
|
||||
fn name() -> &'static str {
|
||||
"calendars"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Template, WebTemplate)]
|
||||
#[template(path = "components/sections/calendars_section.html")]
|
||||
pub struct CalendarsSection {
|
||||
pub user: Principal,
|
||||
pub calendars: Vec<Calendar>,
|
||||
pub deleted_calendars: Vec<Calendar>,
|
||||
}
|
||||
|
||||
pub async fn route_calendars<CS: CalendarStore>(
|
||||
Path(user_id): Path<String>,
|
||||
Extension(cal_store): Extension<Arc<CS>>,
|
||||
user: Principal,
|
||||
) -> impl IntoResponse {
|
||||
if user_id != user.id {
|
||||
return StatusCode::UNAUTHORIZED.into_response();
|
||||
}
|
||||
|
||||
let mut calendars = vec![];
|
||||
for group in user.memberships() {
|
||||
calendars.extend(cal_store.get_calendars(group).await.unwrap());
|
||||
}
|
||||
|
||||
let mut deleted_calendars = vec![];
|
||||
for group in user.memberships() {
|
||||
deleted_calendars.extend(cal_store.get_deleted_calendars(group).await.unwrap());
|
||||
}
|
||||
|
||||
UserPage {
|
||||
section: CalendarsSection {
|
||||
user: user.clone(),
|
||||
calendars,
|
||||
deleted_calendars,
|
||||
},
|
||||
user,
|
||||
}
|
||||
.into_response()
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
pub mod addressbook;
|
||||
pub mod addressbooks;
|
||||
pub mod app_token;
|
||||
pub mod calendar;
|
||||
pub mod calendars;
|
||||
pub mod login;
|
||||
pub mod user;
|
||||
|
||||
@@ -11,19 +11,23 @@ use axum_extra::{TypedHeader, extract::Host};
|
||||
use headers::UserAgent;
|
||||
use http::StatusCode;
|
||||
use rustical_store::{
|
||||
Addressbook, AddressbookStore, Calendar, CalendarStore,
|
||||
AddressbookStore, CalendarStore,
|
||||
auth::{AppToken, AuthenticationProvider, Principal},
|
||||
};
|
||||
|
||||
use crate::pages::user::{Section, UserPage};
|
||||
|
||||
impl Section for ProfileSection {
|
||||
fn name() -> &'static str {
|
||||
"profile"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Template, WebTemplate)]
|
||||
#[template(path = "pages/user.html")]
|
||||
pub struct UserPage {
|
||||
#[template(path = "components/sections/profile_section.html")]
|
||||
pub struct ProfileSection {
|
||||
pub user: Principal,
|
||||
pub app_tokens: Vec<AppToken>,
|
||||
pub calendars: Vec<Calendar>,
|
||||
pub deleted_calendars: Vec<Calendar>,
|
||||
pub addressbooks: Vec<Addressbook>,
|
||||
pub deleted_addressbooks: Vec<Addressbook>,
|
||||
pub is_apple: bool,
|
||||
pub davx5_hostname: Option<String>,
|
||||
}
|
||||
@@ -69,14 +73,13 @@ pub async fn route_user_named<
|
||||
let davx5_hostname = user_agent.as_str().contains("Android").then_some(host);
|
||||
|
||||
UserPage {
|
||||
app_tokens: auth_provider.get_app_tokens(&user.id).await.unwrap(),
|
||||
calendars,
|
||||
deleted_calendars,
|
||||
addressbooks,
|
||||
deleted_addressbooks,
|
||||
section: ProfileSection {
|
||||
user: user.clone(),
|
||||
app_tokens: auth_provider.get_app_tokens(&user.id).await.unwrap(),
|
||||
is_apple,
|
||||
davx5_hostname,
|
||||
},
|
||||
user,
|
||||
is_apple,
|
||||
davx5_hostname,
|
||||
}
|
||||
.into_response()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user