mirror of
https://github.com/lennart-k/rustical.git
synced 2026-01-30 11:48:18 +00:00
Add test for uploading invalid calendar object and fix precondition
This commit is contained in:
@@ -11,7 +11,7 @@ use rustical_ical::CalendarObject;
|
|||||||
use rustical_store::CalendarStore;
|
use rustical_store::CalendarStore;
|
||||||
use rustical_store::auth::Principal;
|
use rustical_store::auth::Principal;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use tracing::{debug, instrument};
|
use tracing::{instrument, warn};
|
||||||
|
|
||||||
#[instrument(skip(cal_store))]
|
#[instrument(skip(cal_store))]
|
||||||
pub async fn get_event<C: CalendarStore>(
|
pub async fn get_event<C: CalendarStore>(
|
||||||
@@ -94,9 +94,13 @@ pub async fn put_event<C: CalendarStore>(
|
|||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(object) = CalendarObject::from_ics(body.clone()) else {
|
let object = match CalendarObject::from_ics(body.clone()) {
|
||||||
debug!("invalid calendar data:\n{body}");
|
Ok(object) => object,
|
||||||
|
Err(err) => {
|
||||||
|
warn!("invalid calendar data:\n{body}");
|
||||||
|
warn!("{err:#?}");
|
||||||
return Err(Error::PreconditionFailed(Precondition::ValidCalendarData));
|
return Err(Error::PreconditionFailed(Precondition::ValidCalendarData));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let etag = object.get_etag();
|
let etag = object.get_etag();
|
||||||
cal_store
|
cal_store
|
||||||
|
|||||||
@@ -79,6 +79,9 @@ impl Error {
|
|||||||
|
|
||||||
impl IntoResponse for Error {
|
impl IntoResponse for Error {
|
||||||
fn into_response(self) -> axum::response::Response {
|
fn into_response(self) -> axum::response::Response {
|
||||||
|
if let Self::PreconditionFailed(precondition) = self {
|
||||||
|
return precondition.into_response();
|
||||||
|
}
|
||||||
if matches!(
|
if matches!(
|
||||||
self.status_code(),
|
self.status_code(),
|
||||||
StatusCode::INTERNAL_SERVER_ERROR | StatusCode::PRECONDITION_FAILED
|
StatusCode::INTERNAL_SERVER_ERROR | StatusCode::PRECONDITION_FAILED
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use rustical_store::{CalendarMetadata, CalendarStore};
|
|||||||
use rustical_store_sqlite::tests::{TestStoreContext, test_store_context};
|
use rustical_store_sqlite::tests::{TestStoreContext, test_store_context};
|
||||||
use tower::ServiceExt;
|
use tower::ServiceExt;
|
||||||
|
|
||||||
fn mkcalendar_template(
|
pub fn mkcalendar_template(
|
||||||
CalendarMetadata {
|
CalendarMetadata {
|
||||||
displayname,
|
displayname,
|
||||||
order: _order,
|
order: _order,
|
||||||
|
|||||||
77
src/integration_tests/caldav/calendar_put.rs
Normal file
77
src/integration_tests/caldav/calendar_put.rs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
use axum::body::Body;
|
||||||
|
use headers::{Authorization, HeaderMapExt};
|
||||||
|
use http::{Request, StatusCode};
|
||||||
|
use rstest::rstest;
|
||||||
|
use rustical_store::CalendarMetadata;
|
||||||
|
use rustical_store_sqlite::tests::{TestStoreContext, test_store_context};
|
||||||
|
use tower::ServiceExt;
|
||||||
|
|
||||||
|
use crate::integration_tests::{
|
||||||
|
ResponseExtractString, caldav::calendar::mkcalendar_template, get_app,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_put_invalid(
|
||||||
|
#[from(test_store_context)]
|
||||||
|
#[future]
|
||||||
|
context: TestStoreContext,
|
||||||
|
) {
|
||||||
|
let context = context.await;
|
||||||
|
let app = get_app(context.clone());
|
||||||
|
|
||||||
|
let calendar_meta = CalendarMetadata {
|
||||||
|
displayname: Some("Calendar".to_string()),
|
||||||
|
description: Some("Description".to_string()),
|
||||||
|
color: Some("#00FF00".to_string()),
|
||||||
|
order: 0,
|
||||||
|
};
|
||||||
|
let (principal, cal_id) = ("user", "calendar");
|
||||||
|
let url = format!("/caldav/principal/{principal}/{cal_id}");
|
||||||
|
|
||||||
|
let mut request = Request::builder()
|
||||||
|
.method("MKCALENDAR")
|
||||||
|
.uri(&url)
|
||||||
|
.body(Body::from(mkcalendar_template(&calendar_meta)))
|
||||||
|
.unwrap();
|
||||||
|
request
|
||||||
|
.headers_mut()
|
||||||
|
.typed_insert(Authorization::basic("user", "pass"));
|
||||||
|
let response = app.clone().oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::CREATED);
|
||||||
|
|
||||||
|
// Invalid calendar data
|
||||||
|
let ical = r"BEGIN:VCALENDAR
|
||||||
|
VERSION:2.0
|
||||||
|
PRODID:-//Example Corp.//CalDAV Client//EN
|
||||||
|
BEGIN:VEVENT
|
||||||
|
UID:20010712T182145Z-123401@example.com
|
||||||
|
DTSTAMP:20060712T182145Z
|
||||||
|
DTSTART:20060714T170000Z
|
||||||
|
RRULE:UNTIL=123
|
||||||
|
DTEND:20060715T040000Z
|
||||||
|
SUMMARY:Bastille Day Party
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR";
|
||||||
|
|
||||||
|
let mut request = Request::builder()
|
||||||
|
.method("PUT")
|
||||||
|
.uri(format!("{url}/qwue23489.ics"))
|
||||||
|
.header("If-None-Match", "*")
|
||||||
|
.header("Content-Type", "text/calendar")
|
||||||
|
.body(Body::from(ical))
|
||||||
|
.unwrap();
|
||||||
|
request
|
||||||
|
.headers_mut()
|
||||||
|
.typed_insert(Authorization::basic("user", "pass"));
|
||||||
|
|
||||||
|
let response = app.clone().oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::PRECONDITION_FAILED);
|
||||||
|
let body = response.extract_string().await;
|
||||||
|
insta::assert_snapshot!(body, @r#"
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<error xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/" xmlns:PUSH="https://bitfire.at/webdav-push">
|
||||||
|
<CAL:valid-calendar-data/>
|
||||||
|
</error>
|
||||||
|
"#);
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ use tower::ServiceExt;
|
|||||||
|
|
||||||
mod calendar;
|
mod calendar;
|
||||||
mod calendar_import;
|
mod calendar_import;
|
||||||
|
mod calendar_put;
|
||||||
mod calendar_report;
|
mod calendar_report;
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
|
|||||||
Reference in New Issue
Block a user