Compare commits
5 Commits
ac1164fd81
...
fd80624429
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd80624429 | ||
|
|
b530dcaa69 | ||
|
|
0821573041 | ||
|
|
703c9ee2f5 | ||
|
|
5854ad291d |
@@ -39,19 +39,13 @@ impl AuthService {
|
|||||||
request.username.clone(),
|
request.username.clone(),
|
||||||
request.password.clone(),
|
request.password.clone(),
|
||||||
);
|
);
|
||||||
println!("📝 Created CalDAV config");
|
|
||||||
|
|
||||||
// Test authentication against CalDAV server
|
// Test authentication against CalDAV server
|
||||||
let caldav_client = CalDAVClient::new(caldav_config.clone());
|
let caldav_client = CalDAVClient::new(caldav_config.clone());
|
||||||
println!("🔗 Created CalDAV client, attempting to discover calendars...");
|
|
||||||
|
|
||||||
// Try to discover calendars as an authentication test
|
// Try to discover calendars as an authentication test
|
||||||
match caldav_client.discover_calendars().await {
|
match caldav_client.discover_calendars().await {
|
||||||
Ok(calendars) => {
|
Ok(_calendars) => {
|
||||||
println!(
|
|
||||||
"✅ Authentication successful! Found {} calendars",
|
|
||||||
calendars.len()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Find or create user in database
|
// Find or create user in database
|
||||||
let user_repo = UserRepository::new(&self.db);
|
let user_repo = UserRepository::new(&self.db);
|
||||||
|
|||||||
@@ -167,8 +167,6 @@ impl CalDAVClient {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let basic_auth = self.config.get_basic_auth();
|
let basic_auth = self.config.get_basic_auth();
|
||||||
println!("🔑 REPORT Basic Auth: Basic {}", basic_auth);
|
|
||||||
println!("🌐 REPORT URL: {}", url);
|
|
||||||
|
|
||||||
let response = self
|
let response = self
|
||||||
.http_client
|
.http_client
|
||||||
@@ -349,6 +347,8 @@ impl CalDAVClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
full_prop.push_str(&format!(":{}", prop_value));
|
full_prop.push_str(&format!(":{}", prop_value));
|
||||||
|
|
||||||
|
|
||||||
full_properties.insert(prop_name, full_prop);
|
full_properties.insert(prop_name, full_prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,6 +358,13 @@ impl CalDAVClient {
|
|||||||
.ok_or_else(|| CalDAVError::ParseError("Missing UID field".to_string()))?
|
.ok_or_else(|| CalDAVError::ParseError("Missing UID field".to_string()))?
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
|
// Determine if it's an all-day event FIRST by checking for VALUE=DATE parameter per RFC 5545
|
||||||
|
let empty_string = String::new();
|
||||||
|
let dtstart_raw = full_properties.get("DTSTART").unwrap_or(&empty_string);
|
||||||
|
let dtstart_value = properties.get("DTSTART").unwrap_or(&empty_string);
|
||||||
|
let all_day = dtstart_raw.contains("VALUE=DATE") || (!dtstart_value.contains("T") && dtstart_value.len() == 8);
|
||||||
|
|
||||||
|
|
||||||
// Parse start time (required)
|
// Parse start time (required)
|
||||||
let start_prop = properties
|
let start_prop = properties
|
||||||
.get("DTSTART")
|
.get("DTSTART")
|
||||||
@@ -375,11 +382,6 @@ impl CalDAVClient {
|
|||||||
(None, None)
|
(None, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine if it's an all-day event by checking for VALUE=DATE parameter
|
|
||||||
let empty_string = String::new();
|
|
||||||
let dtstart_raw = properties.get("DTSTART").unwrap_or(&empty_string);
|
|
||||||
let all_day = dtstart_raw.contains("VALUE=DATE") || (!dtstart_raw.contains("T") && dtstart_raw.len() == 8);
|
|
||||||
|
|
||||||
// Parse status
|
// Parse status
|
||||||
let status = properties
|
let status = properties
|
||||||
.get("STATUS")
|
.get("STATUS")
|
||||||
@@ -582,11 +584,9 @@ impl CalDAVClient {
|
|||||||
pub async fn discover_calendars(&self) -> Result<Vec<String>, CalDAVError> {
|
pub async fn discover_calendars(&self) -> Result<Vec<String>, CalDAVError> {
|
||||||
// First, try to discover user calendars if we have a calendar path in config
|
// First, try to discover user calendars if we have a calendar path in config
|
||||||
if let Some(calendar_path) = &self.config.calendar_path {
|
if let Some(calendar_path) = &self.config.calendar_path {
|
||||||
println!("Using configured calendar path: {}", calendar_path);
|
|
||||||
return Ok(vec![calendar_path.clone()]);
|
return Ok(vec![calendar_path.clone()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("No calendar path configured, discovering calendars...");
|
|
||||||
|
|
||||||
// Try different common CalDAV discovery paths
|
// Try different common CalDAV discovery paths
|
||||||
// Note: paths should be relative to the server URL base
|
// Note: paths should be relative to the server URL base
|
||||||
@@ -599,20 +599,16 @@ impl CalDAVClient {
|
|||||||
let mut has_valid_caldav_response = false;
|
let mut has_valid_caldav_response = false;
|
||||||
|
|
||||||
for path in discovery_paths {
|
for path in discovery_paths {
|
||||||
println!("Trying discovery path: {}", path);
|
|
||||||
match self.discover_calendars_at_path(&path).await {
|
match self.discover_calendars_at_path(&path).await {
|
||||||
Ok(calendars) => {
|
Ok(calendars) => {
|
||||||
println!("Found {} calendar(s) at {}", calendars.len(), path);
|
|
||||||
has_valid_caldav_response = true;
|
has_valid_caldav_response = true;
|
||||||
all_calendars.extend(calendars);
|
all_calendars.extend(calendars);
|
||||||
}
|
}
|
||||||
Err(CalDAVError::ServerError(status)) => {
|
Err(CalDAVError::ServerError(_status)) => {
|
||||||
// HTTP error - this might be expected for some paths, continue trying
|
// HTTP error - this might be expected for some paths, continue trying
|
||||||
println!("Discovery path {} returned HTTP {}, trying next path", path, status);
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// Network or other error - this suggests the server isn't reachable or isn't CalDAV
|
// Network or other error - this suggests the server isn't reachable or isn't CalDAV
|
||||||
println!("Discovery failed for path {}: {:?}", path, e);
|
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -669,7 +665,6 @@ impl CalDAVClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let body = response.text().await.map_err(CalDAVError::RequestError)?;
|
let body = response.text().await.map_err(CalDAVError::RequestError)?;
|
||||||
println!("Discovery response for {}: {}", path, body);
|
|
||||||
|
|
||||||
let mut calendar_paths = Vec::new();
|
let mut calendar_paths = Vec::new();
|
||||||
|
|
||||||
@@ -680,7 +675,6 @@ impl CalDAVClient {
|
|||||||
|
|
||||||
// Extract href first
|
// Extract href first
|
||||||
if let Some(href) = self.extract_xml_content(response_content, "href") {
|
if let Some(href) = self.extract_xml_content(response_content, "href") {
|
||||||
println!("🔍 Checking resource: {}", href);
|
|
||||||
|
|
||||||
// Check if this is a calendar collection by looking for supported-calendar-component-set
|
// Check if this is a calendar collection by looking for supported-calendar-component-set
|
||||||
// This indicates it's an actual calendar that can contain events
|
// This indicates it's an actual calendar that can contain events
|
||||||
@@ -704,14 +698,10 @@ impl CalDAVClient {
|
|||||||
&& !href.ends_with("/calendars/")
|
&& !href.ends_with("/calendars/")
|
||||||
&& href.ends_with('/')
|
&& href.ends_with('/')
|
||||||
{
|
{
|
||||||
println!("📅 Found calendar collection: {}", href);
|
|
||||||
calendar_paths.push(href);
|
calendar_paths.push(href);
|
||||||
} else {
|
} else {
|
||||||
println!("❌ Skipping system/root directory: {}", href);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("ℹ️ Not a calendar collection: {} (is_calendar: {}, has_collection: {})",
|
|
||||||
href, is_calendar, has_collection);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -786,14 +776,24 @@ impl CalDAVClient {
|
|||||||
return Ok((dt.naive_utc(), Some("UTC".to_string())));
|
return Ok((dt.naive_utc(), Some("UTC".to_string())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try parsing as naive datetime
|
// Special handling for date-only format (all-day events)
|
||||||
if let Ok(naive_dt) = chrono::NaiveDateTime::parse_from_str(datetime_part, format) {
|
if *format == "%Y%m%d" {
|
||||||
// Per RFC 5545: if no TZID parameter is provided, treat as UTC
|
if let Ok(date) = chrono::NaiveDate::parse_from_str(datetime_part, format) {
|
||||||
let tz = timezone_id.unwrap_or_else(|| "UTC".to_string());
|
// Convert date to midnight datetime for all-day events
|
||||||
|
let naive_dt = date.and_hms_opt(0, 0, 0).unwrap();
|
||||||
// If it's UTC, the naive time is already correct
|
let tz = timezone_id.unwrap_or_else(|| "UTC".to_string());
|
||||||
// If it's a local timezone, we store the naive time and the timezone ID
|
return Ok((naive_dt, Some(tz)));
|
||||||
return Ok((naive_dt, Some(tz)));
|
}
|
||||||
|
} else {
|
||||||
|
// Try parsing as naive datetime for time-based formats
|
||||||
|
if let Ok(naive_dt) = chrono::NaiveDateTime::parse_from_str(datetime_part, format) {
|
||||||
|
// Per RFC 5545: if no TZID parameter is provided, treat as UTC
|
||||||
|
let tz = timezone_id.unwrap_or_else(|| "UTC".to_string());
|
||||||
|
|
||||||
|
// If it's UTC, the naive time is already correct
|
||||||
|
// If it's a local timezone, we store the naive time and the timezone ID
|
||||||
|
return Ok((naive_dt, Some(tz)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,10 +82,6 @@ pub async fn get_user_info(
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| ApiError::Internal(format!("Failed to discover calendars: {}", e)))?;
|
.map_err(|e| ApiError::Internal(format!("Failed to discover calendars: {}", e)))?;
|
||||||
|
|
||||||
println!(
|
|
||||||
"✅ Authentication successful! Found {} calendars",
|
|
||||||
calendar_paths.len()
|
|
||||||
);
|
|
||||||
|
|
||||||
let calendars: Vec<CalendarInfo> = calendar_paths
|
let calendars: Vec<CalendarInfo> = calendar_paths
|
||||||
.iter()
|
.iter()
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ pub async fn get_calendar_events(
|
|||||||
// Extract and verify token
|
// Extract and verify token
|
||||||
let token = extract_bearer_token(&headers)?;
|
let token = extract_bearer_token(&headers)?;
|
||||||
let password = extract_password_header(&headers)?;
|
let password = extract_password_header(&headers)?;
|
||||||
println!("🔑 API call with password length: {}", password.len());
|
|
||||||
|
|
||||||
// Create CalDAV config from token and password
|
// Create CalDAV config from token and password
|
||||||
let config = state
|
let config = state
|
||||||
@@ -127,7 +126,6 @@ pub async fn get_calendar_events(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("📅 Returning {} events", all_events.len());
|
|
||||||
Ok(Json(all_events))
|
Ok(Json(all_events))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -491,26 +491,18 @@ fn deduplicate_events(mut events: Vec<VEvent>) -> Vec<VEvent> {
|
|||||||
let mut uid_groups: HashMap<String, Vec<VEvent>> = HashMap::new();
|
let mut uid_groups: HashMap<String, Vec<VEvent>> = HashMap::new();
|
||||||
|
|
||||||
for event in events.drain(..) {
|
for event in events.drain(..) {
|
||||||
// Debug logging to understand what's happening
|
|
||||||
println!("🔍 Event: '{}' at {} (RRULE: {}) - UID: {}",
|
|
||||||
event.summary.as_ref().unwrap_or(&"No Title".to_string()),
|
|
||||||
event.dtstart.format("%Y-%m-%d %H:%M"),
|
|
||||||
if event.rrule.is_some() { "Yes" } else { "No" },
|
|
||||||
event.uid
|
|
||||||
);
|
|
||||||
|
|
||||||
uid_groups.entry(event.uid.clone()).or_insert_with(Vec::new).push(event);
|
uid_groups.entry(event.uid.clone()).or_insert_with(Vec::new).push(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut uid_deduplicated_events = Vec::new();
|
let mut uid_deduplicated_events = Vec::new();
|
||||||
|
|
||||||
for (uid, mut events_with_uid) in uid_groups.drain() {
|
for (_uid, mut events_with_uid) in uid_groups.drain() {
|
||||||
if events_with_uid.len() == 1 {
|
if events_with_uid.len() == 1 {
|
||||||
// Only one event with this UID, keep it
|
// Only one event with this UID, keep it
|
||||||
uid_deduplicated_events.push(events_with_uid.into_iter().next().unwrap());
|
uid_deduplicated_events.push(events_with_uid.into_iter().next().unwrap());
|
||||||
} else {
|
} else {
|
||||||
// Multiple events with same UID - prefer recurring over non-recurring
|
// Multiple events with same UID - prefer recurring over non-recurring
|
||||||
println!("🔍 Found {} events with UID '{}'", events_with_uid.len(), uid);
|
|
||||||
|
|
||||||
// Sort by preference: recurring events first, then by completeness
|
// Sort by preference: recurring events first, then by completeness
|
||||||
events_with_uid.sort_by(|a, b| {
|
events_with_uid.sort_by(|a, b| {
|
||||||
@@ -529,10 +521,6 @@ fn deduplicate_events(mut events: Vec<VEvent>) -> Vec<VEvent> {
|
|||||||
|
|
||||||
// Keep the first (preferred) event
|
// Keep the first (preferred) event
|
||||||
let preferred_event = events_with_uid.into_iter().next().unwrap();
|
let preferred_event = events_with_uid.into_iter().next().unwrap();
|
||||||
println!("🔄 UID dedup: Keeping '{}' (RRULE: {})",
|
|
||||||
preferred_event.summary.as_ref().unwrap_or(&"No Title".to_string()),
|
|
||||||
if preferred_event.rrule.is_some() { "Yes" } else { "No" }
|
|
||||||
);
|
|
||||||
uid_deduplicated_events.push(preferred_event);
|
uid_deduplicated_events.push(preferred_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ pub fn App() -> Html {
|
|||||||
match auth_service.verify_token(&stored_token).await {
|
match auth_service.verify_token(&stored_token).await {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
// Token is valid, set it
|
// Token is valid, set it
|
||||||
web_sys::console::log_1(&"✅ Stored auth token is valid".into());
|
|
||||||
auth_token.set(Some(stored_token));
|
auth_token.set(Some(stored_token));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -915,8 +914,8 @@ pub fn App() -> Html {
|
|||||||
original_event,
|
original_event,
|
||||||
new_start,
|
new_start,
|
||||||
new_end,
|
new_end,
|
||||||
preserve_rrule,
|
_preserve_rrule,
|
||||||
until_date,
|
_until_date,
|
||||||
update_scope,
|
update_scope,
|
||||||
occurrence_date,
|
occurrence_date,
|
||||||
): (
|
): (
|
||||||
@@ -1198,10 +1197,6 @@ pub fn App() -> Html {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
// Debug logging
|
|
||||||
web_sys::console::log_1(
|
|
||||||
&format!("App rendering: auth_token = {:?}", auth_token.is_some()).into(),
|
|
||||||
);
|
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
@@ -1479,7 +1474,7 @@ pub fn App() -> Html {
|
|||||||
let calendar_management_modal_open = calendar_management_modal_open.clone();
|
let calendar_management_modal_open = calendar_management_modal_open.clone();
|
||||||
|
|
||||||
wasm_bindgen_futures::spawn_local(async move {
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
let calendar_service = CalendarService::new();
|
let _calendar_service = CalendarService::new();
|
||||||
match CalendarService::get_external_calendars().await {
|
match CalendarService::get_external_calendars().await {
|
||||||
Ok(calendars) => {
|
Ok(calendars) => {
|
||||||
external_calendars.set(calendars);
|
external_calendars.set(calendars);
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ pub fn month_view(props: &MonthViewProps) -> Html {
|
|||||||
"#3B82F6".to_string()
|
"#3B82F6".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class="calendar-grid">
|
<div class="calendar-grid">
|
||||||
// Weekday headers
|
// Weekday headers
|
||||||
|
|||||||
@@ -2,17 +2,7 @@ use crate::components::CalendarListItem;
|
|||||||
use crate::services::calendar_service::{UserInfo, ExternalCalendar};
|
use crate::services::calendar_service::{UserInfo, ExternalCalendar};
|
||||||
use web_sys::HtmlSelectElement;
|
use web_sys::HtmlSelectElement;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::prelude::*;
|
|
||||||
|
|
||||||
#[derive(Clone, Routable, PartialEq)]
|
|
||||||
pub enum Route {
|
|
||||||
#[at("/")]
|
|
||||||
Home,
|
|
||||||
#[at("/login")]
|
|
||||||
Login,
|
|
||||||
#[at("/calendar")]
|
|
||||||
Calendar,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum ViewMode {
|
pub enum ViewMode {
|
||||||
|
|||||||
@@ -348,6 +348,7 @@ pub fn week_view(props: &WeekViewProps) -> Html {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class="week-view-container">
|
<div class="week-view-container">
|
||||||
// Header with weekday names and dates
|
// Header with weekday names and dates
|
||||||
|
|||||||
@@ -247,6 +247,8 @@ impl CalendarService {
|
|||||||
if resp.ok() {
|
if resp.ok() {
|
||||||
let events: Vec<CalendarEvent> = serde_json::from_str(&text_string)
|
let events: Vec<CalendarEvent> = serde_json::from_str(&text_string)
|
||||||
.map_err(|e| format!("JSON parsing failed: {}", e))?;
|
.map_err(|e| format!("JSON parsing failed: {}", e))?;
|
||||||
|
|
||||||
|
|
||||||
Ok(events)
|
Ok(events)
|
||||||
} else {
|
} else {
|
||||||
Err(format!(
|
Err(format!(
|
||||||
@@ -277,14 +279,15 @@ impl CalendarService {
|
|||||||
|
|
||||||
/// Convert UTC events to local timezone for display
|
/// Convert UTC events to local timezone for display
|
||||||
fn convert_utc_to_local(mut event: VEvent) -> VEvent {
|
fn convert_utc_to_local(mut event: VEvent) -> VEvent {
|
||||||
|
// All-day events should not have timezone conversions applied
|
||||||
|
if event.all_day {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if event times are in UTC (legacy events from before timezone migration)
|
// Check if event times are in UTC (legacy events from before timezone migration)
|
||||||
let is_utc_event = event.dtstart_tzid.as_ref().map_or(true, |tz| tz == "UTC");
|
let is_utc_event = event.dtstart_tzid.as_ref().map_or(true, |tz| tz == "UTC");
|
||||||
|
|
||||||
if is_utc_event {
|
if is_utc_event {
|
||||||
web_sys::console::log_1(&format!(
|
|
||||||
"🕐 Converting UTC event '{}' to local time",
|
|
||||||
event.summary.as_deref().unwrap_or("Untitled")
|
|
||||||
).into());
|
|
||||||
|
|
||||||
// Get current timezone offset (convert from UTC to local)
|
// Get current timezone offset (convert from UTC to local)
|
||||||
let date = js_sys::Date::new_0();
|
let date = js_sys::Date::new_0();
|
||||||
@@ -330,38 +333,10 @@ impl CalendarService {
|
|||||||
// Convert UTC events to local time for proper display
|
// Convert UTC events to local time for proper display
|
||||||
let event = Self::convert_utc_to_local(event);
|
let event = Self::convert_utc_to_local(event);
|
||||||
if let Some(ref rrule) = event.rrule {
|
if let Some(ref rrule) = event.rrule {
|
||||||
web_sys::console::log_1(
|
|
||||||
&format!(
|
|
||||||
"📅 Processing recurring VEvent '{}' with RRULE: {}",
|
|
||||||
event.summary.as_deref().unwrap_or("Untitled"),
|
|
||||||
rrule
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Log if event has exception dates
|
|
||||||
if !event.exdate.is_empty() {
|
|
||||||
web_sys::console::log_1(
|
|
||||||
&format!(
|
|
||||||
"📅 VEvent '{}' has {} exception dates: {:?}",
|
|
||||||
event.summary.as_deref().unwrap_or("Untitled"),
|
|
||||||
event.exdate.len(),
|
|
||||||
event.exdate
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate occurrences for recurring events using VEvent
|
// Generate occurrences for recurring events using VEvent
|
||||||
let occurrences = Self::generate_occurrences(&event, rrule, start_range, end_range);
|
let occurrences = Self::generate_occurrences(&event, rrule, start_range, end_range);
|
||||||
web_sys::console::log_1(
|
|
||||||
&format!(
|
|
||||||
"📅 Generated {} occurrences for VEvent '{}'",
|
|
||||||
occurrences.len(),
|
|
||||||
event.summary.as_deref().unwrap_or("Untitled")
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
expanded_events.extend(occurrences);
|
expanded_events.extend(occurrences);
|
||||||
} else {
|
} else {
|
||||||
// Non-recurring event - add as-is
|
// Non-recurring event - add as-is
|
||||||
@@ -383,7 +358,6 @@ impl CalendarService {
|
|||||||
|
|
||||||
// Parse RRULE components
|
// Parse RRULE components
|
||||||
let rrule_upper = rrule.to_uppercase();
|
let rrule_upper = rrule.to_uppercase();
|
||||||
web_sys::console::log_1(&format!("🔄 Parsing RRULE: {}", rrule_upper).into());
|
|
||||||
|
|
||||||
let components: HashMap<String, String> = rrule_upper
|
let components: HashMap<String, String> = rrule_upper
|
||||||
.split(';')
|
.split(';')
|
||||||
@@ -438,8 +412,7 @@ impl CalendarService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(until) = until_date {
|
if let Some(_until) = until_date {
|
||||||
web_sys::console::log_1(&format!("📅 RRULE has UNTIL: {}", until).into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let start_date = base_event.dtstart.date();
|
let start_date = base_event.dtstart.date();
|
||||||
@@ -453,10 +426,6 @@ impl CalendarService {
|
|||||||
let current_datetime = base_event.dtstart
|
let current_datetime = base_event.dtstart
|
||||||
+ Duration::days(current_date.signed_duration_since(start_date).num_days());
|
+ Duration::days(current_date.signed_duration_since(start_date).num_days());
|
||||||
if current_datetime > until {
|
if current_datetime > until {
|
||||||
web_sys::console::log_1(
|
|
||||||
&format!("🛑 Stopping at {} due to UNTIL {}", current_datetime, until)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -653,13 +622,6 @@ impl CalendarService {
|
|||||||
let days_diff = occurrence_date.signed_duration_since(start_date).num_days();
|
let days_diff = occurrence_date.signed_duration_since(start_date).num_days();
|
||||||
let occurrence_datetime = base_event.dtstart + Duration::days(days_diff);
|
let occurrence_datetime = base_event.dtstart + Duration::days(days_diff);
|
||||||
if occurrence_datetime > until {
|
if occurrence_datetime > until {
|
||||||
web_sys::console::log_1(
|
|
||||||
&format!(
|
|
||||||
"🛑 Stopping at {} due to UNTIL {}",
|
|
||||||
occurrence_datetime, until
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
return occurrences;
|
return occurrences;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -779,13 +741,6 @@ impl CalendarService {
|
|||||||
occurrence_date.signed_duration_since(start_date).num_days();
|
occurrence_date.signed_duration_since(start_date).num_days();
|
||||||
let occurrence_datetime = base_event.dtstart + Duration::days(days_diff);
|
let occurrence_datetime = base_event.dtstart + Duration::days(days_diff);
|
||||||
if occurrence_datetime > until {
|
if occurrence_datetime > until {
|
||||||
web_sys::console::log_1(
|
|
||||||
&format!(
|
|
||||||
"🛑 Stopping at {} due to UNTIL {}",
|
|
||||||
occurrence_datetime, until
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
return occurrences;
|
return occurrences;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2146,7 +2101,6 @@ impl CalendarService {
|
|||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct ExternalCalendarEventsResponse {
|
struct ExternalCalendarEventsResponse {
|
||||||
events: Vec<VEvent>,
|
events: Vec<VEvent>,
|
||||||
last_fetched: chrono::DateTime<chrono::Utc>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let response: ExternalCalendarEventsResponse = serde_wasm_bindgen::from_value(json)
|
let response: ExternalCalendarEventsResponse = serde_wasm_bindgen::from_value(json)
|
||||||
|
|||||||
Reference in New Issue
Block a user