mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-14 08:12:24 +00:00
Minor frontend improvements, feature to create calendar
This commit is contained in:
@@ -34,7 +34,7 @@ use crate::{
|
||||
routes::{
|
||||
addressbook::{route_addressbook, route_addressbook_restore},
|
||||
app_token::{route_delete_app_token, route_post_app_token},
|
||||
calendar::{route_calendar, route_calendar_restore},
|
||||
calendar::{route_calendar, route_calendar_restore, route_create_calendar},
|
||||
login::{route_get_login, route_post_login, route_post_logout},
|
||||
user::{route_get_home, route_root, route_user_named},
|
||||
},
|
||||
@@ -66,6 +66,7 @@ pub fn frontend_router<
|
||||
post(route_delete_app_token::<AP>),
|
||||
)
|
||||
// Calendar
|
||||
.route("/user/{user}/calendar", post(route_create_calendar::<CS>))
|
||||
.route(
|
||||
"/user/{user}/calendar/{calendar}",
|
||||
get(route_calendar::<CS>),
|
||||
|
||||
@@ -3,14 +3,16 @@ use std::sync::Arc;
|
||||
use askama::Template;
|
||||
use askama_web::WebTemplate;
|
||||
use axum::{
|
||||
Extension,
|
||||
Extension, Form,
|
||||
extract::Path,
|
||||
response::{IntoResponse, Redirect, Response},
|
||||
};
|
||||
use axum_extra::TypedHeader;
|
||||
use headers::Referer;
|
||||
use http::StatusCode;
|
||||
use rustical_ical::CalendarObjectType;
|
||||
use rustical_store::{Calendar, CalendarStore, auth::User};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
#[derive(Template, WebTemplate)]
|
||||
#[template(path = "pages/calendar.html")]
|
||||
@@ -32,6 +34,82 @@ pub async fn route_calendar<C: CalendarStore>(
|
||||
.into_response())
|
||||
}
|
||||
|
||||
fn empty_to_none<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let val: Option<String> = Deserialize::deserialize(deserializer)?;
|
||||
Ok(val.filter(|val| !val.is_empty()))
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
pub struct PutCalendarForm {
|
||||
id: String,
|
||||
#[serde(deserialize_with = "empty_to_none")]
|
||||
displayname: Option<String>,
|
||||
#[serde(deserialize_with = "empty_to_none")]
|
||||
description: Option<String>,
|
||||
#[serde(deserialize_with = "empty_to_none")]
|
||||
color: Option<String>,
|
||||
#[serde(deserialize_with = "empty_to_none")]
|
||||
subscription_url: Option<String>,
|
||||
comp_event: Option<String>,
|
||||
comp_todo: Option<String>,
|
||||
comp_journal: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn route_create_calendar<C: CalendarStore>(
|
||||
Path(owner): Path<String>,
|
||||
Extension(store): Extension<Arc<C>>,
|
||||
user: User,
|
||||
Form(PutCalendarForm {
|
||||
id,
|
||||
displayname,
|
||||
description,
|
||||
color,
|
||||
subscription_url,
|
||||
comp_event,
|
||||
comp_todo,
|
||||
comp_journal,
|
||||
}): Form<PutCalendarForm>,
|
||||
) -> Result<Response, rustical_store::Error> {
|
||||
if !user.is_principal(&owner) {
|
||||
return Ok(StatusCode::UNAUTHORIZED.into_response());
|
||||
}
|
||||
|
||||
assert!(!id.is_empty());
|
||||
|
||||
let mut comps = vec![];
|
||||
if comp_event.is_some() {
|
||||
comps.push(CalendarObjectType::Event);
|
||||
}
|
||||
if comp_todo.is_some() {
|
||||
comps.push(CalendarObjectType::Todo);
|
||||
}
|
||||
if comp_journal.is_some() {
|
||||
comps.push(CalendarObjectType::Journal);
|
||||
}
|
||||
|
||||
let cal = Calendar {
|
||||
id: id.to_owned(),
|
||||
displayname,
|
||||
description,
|
||||
color,
|
||||
subscription_url,
|
||||
principal: user.id,
|
||||
components: comps,
|
||||
order: 0,
|
||||
timezone_id: None,
|
||||
timezone: None,
|
||||
synctoken: 0,
|
||||
deleted_at: None,
|
||||
push_topic: uuid::Uuid::new_v4().to_string(),
|
||||
};
|
||||
|
||||
store.insert_calendar(cal).await?;
|
||||
Ok(Redirect::to(&id).into_response())
|
||||
}
|
||||
|
||||
pub async fn route_calendar_restore<CS: CalendarStore>(
|
||||
Path((owner, cal_id)): Path<(String, String)>,
|
||||
Extension(store): Extension<Arc<CS>>,
|
||||
|
||||
Reference in New Issue
Block a user