From 9802d51acc3f13ccfda84d03d5f8f569e4e2f9f4 Mon Sep 17 00:00:00 2001 From: Mahmoud-Emad Date: Tue, 3 Jun 2025 15:12:53 +0300 Subject: [PATCH] feat: Migrate to hero-models for calendar event data - Replaced custom `CalendarEvent` model with `heromodels`' `Event` model. - Updated database interactions and controller logic to use the new model. - Removed unnecessary `CalendarEvent` model and related code. - Updated views to reflect changes in event data structure. --- actix_mvc_app/src/controllers/calendar.rs | 19 ++----- actix_mvc_app/src/db/calendar.rs | 2 +- actix_mvc_app/src/db/mod.rs | 1 + actix_mvc_app/src/models/calendar.rs | 61 +-------------------- actix_mvc_app/src/models/mod.rs | 2 +- actix_mvc_app/src/utils/mod.rs | 2 +- actix_mvc_app/src/utils/redis_service.rs | 60 ++++++++++---------- actix_mvc_app/src/views/calendar/index.html | 11 ++-- 8 files changed, 47 insertions(+), 111 deletions(-) diff --git a/actix_mvc_app/src/controllers/calendar.rs b/actix_mvc_app/src/controllers/calendar.rs index ee99d9e..e84c55c 100644 --- a/actix_mvc_app/src/controllers/calendar.rs +++ b/actix_mvc_app/src/controllers/calendar.rs @@ -8,8 +8,9 @@ use tera::Tera; use crate::db::calendar::{ add_event_to_calendar, create_new_event, delete_event, get_events, get_or_create_user_calendar, }; -use crate::models::{CalendarEvent, CalendarViewMode}; +use crate::models::CalendarViewMode; use crate::utils::render_template; +use heromodels::models::calendar::Event; use heromodels_core::Model; /// Controller for handling calendar-related routes @@ -138,23 +139,13 @@ impl CalendarController { // Get events from database let events = match get_events() { Ok(db_events) => { - // Filter events for the date range and convert to CalendarEvent format + // Filter events for the date range db_events .into_iter() .filter(|event| { // Event overlaps with the date range event.start_time < end_date && event.end_time > start_date }) - .map(|event| CalendarEvent { - id: event.get_id().to_string(), - title: event.title.clone(), - description: event.description.clone().unwrap_or_default(), - start_time: event.start_time, - end_time: event.end_time, - color: event.color.clone().unwrap_or_else(|| "#4285F4".to_string()), - all_day: event.all_day, - user_id: event.created_by.map(|id| id.to_string()), - }) .collect() } Err(e) => { @@ -574,7 +565,7 @@ pub struct EventForm { #[derive(Debug, Serialize)] struct CalendarDay { day: u32, - events: Vec, + events: Vec, is_current_month: bool, } @@ -583,5 +574,5 @@ struct CalendarDay { struct CalendarMonth { month: u32, name: String, - events: Vec, + events: Vec, } diff --git a/actix_mvc_app/src/db/calendar.rs b/actix_mvc_app/src/db/calendar.rs index b71458c..5af4c8d 100644 --- a/actix_mvc_app/src/db/calendar.rs +++ b/actix_mvc_app/src/db/calendar.rs @@ -1,7 +1,7 @@ use chrono::{DateTime, Utc}; use heromodels::{ db::{Collection, Db}, - models::calendar::{AttendanceStatus, Attendee, Calendar, Event, EventStatus}, + models::calendar::{AttendanceStatus, Attendee, Calendar, Event}, }; use super::db::get_db; diff --git a/actix_mvc_app/src/db/mod.rs b/actix_mvc_app/src/db/mod.rs index 0b27adf..951511e 100644 --- a/actix_mvc_app/src/db/mod.rs +++ b/actix_mvc_app/src/db/mod.rs @@ -1,3 +1,4 @@ pub mod calendar; +pub mod contracts; pub mod db; pub mod governance; diff --git a/actix_mvc_app/src/models/calendar.rs b/actix_mvc_app/src/models/calendar.rs index d62a77e..d90f1f3 100644 --- a/actix_mvc_app/src/models/calendar.rs +++ b/actix_mvc_app/src/models/calendar.rs @@ -1,61 +1,4 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -/// Represents a calendar event -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CalendarEvent { - /// Unique identifier for the event - pub id: String, - /// Title of the event - pub title: String, - /// Description of the event - pub description: String, - /// Start time of the event - pub start_time: DateTime, - /// End time of the event - pub end_time: DateTime, - /// Color of the event (hex code) - pub color: String, - /// Whether the event is an all-day event - pub all_day: bool, - /// User ID of the event creator - pub user_id: Option, -} - -impl CalendarEvent { - /// Creates a new calendar event - pub fn new( - title: String, - description: String, - start_time: DateTime, - end_time: DateTime, - color: Option, - all_day: bool, - user_id: Option, - ) -> Self { - Self { - id: Uuid::new_v4().to_string(), - title, - description, - start_time, - end_time, - color: color.unwrap_or_else(|| "#4285F4".to_string()), // Google Calendar blue - all_day, - user_id, - } - } - - /// Converts the event to a JSON string - pub fn to_json(&self) -> Result { - serde_json::to_string(self) - } - - /// Creates an event from a JSON string - pub fn from_json(json: &str) -> Result { - serde_json::from_str(json) - } -} +// No imports needed for this module currently /// Represents a view mode for the calendar #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -91,4 +34,4 @@ impl CalendarViewMode { Self::Day => "day", } } -} \ No newline at end of file +} diff --git a/actix_mvc_app/src/models/mod.rs b/actix_mvc_app/src/models/mod.rs index d225c4b..cc9f331 100644 --- a/actix_mvc_app/src/models/mod.rs +++ b/actix_mvc_app/src/models/mod.rs @@ -10,7 +10,7 @@ pub mod ticket; pub mod user; // Re-export models for easier imports -pub use calendar::{CalendarEvent, CalendarViewMode}; +pub use calendar::CalendarViewMode; pub use defi::initialize_mock_data; pub use ticket::{Ticket, TicketComment, TicketPriority, TicketStatus}; pub use user::User; diff --git a/actix_mvc_app/src/utils/mod.rs b/actix_mvc_app/src/utils/mod.rs index dbd8118..dcc2732 100644 --- a/actix_mvc_app/src/utils/mod.rs +++ b/actix_mvc_app/src/utils/mod.rs @@ -7,7 +7,7 @@ use tera::{self, Context, Function, Tera, Value}; pub mod redis_service; // Re-export for easier imports -pub use redis_service::RedisCalendarService; +// pub use redis_service::RedisCalendarService; // Currently unused /// Error type for template rendering #[derive(Debug)] diff --git a/actix_mvc_app/src/utils/redis_service.rs b/actix_mvc_app/src/utils/redis_service.rs index f7244a4..76d89f5 100644 --- a/actix_mvc_app/src/utils/redis_service.rs +++ b/actix_mvc_app/src/utils/redis_service.rs @@ -1,7 +1,7 @@ +use heromodels::models::Event as CalendarEvent; +use lazy_static::lazy_static; use redis::{Client, Commands, Connection, RedisError}; use std::sync::{Arc, Mutex}; -use lazy_static::lazy_static; -use crate::models::CalendarEvent; // Create a lazy static Redis client that can be used throughout the application lazy_static! { @@ -11,21 +11,21 @@ lazy_static! { /// Initialize the Redis client pub fn init_redis_client(redis_url: &str) -> Result<(), RedisError> { let client = redis::Client::open(redis_url)?; - + // Test the connection let _: Connection = client.get_connection()?; - + // Store the client in the lazy static let mut client_guard = REDIS_CLIENT.lock().unwrap(); *client_guard = Some(client); - + Ok(()) } /// Get a Redis connection pub fn get_connection() -> Result { let client_guard = REDIS_CLIENT.lock().unwrap(); - + if let Some(client) = &*client_guard { client.get_connection() } else { @@ -42,14 +42,14 @@ pub struct RedisCalendarService; impl RedisCalendarService { /// Key prefix for calendar events const EVENT_KEY_PREFIX: &'static str = "calendar:event:"; - + /// Key for the set of all event IDs const ALL_EVENTS_KEY: &'static str = "calendar:all_events"; - + /// Save a calendar event to Redis pub fn save_event(event: &CalendarEvent) -> Result<(), RedisError> { let mut conn = get_connection()?; - + // Convert the event to JSON let json = event.to_json().map_err(|e| { RedisError::from(std::io::Error::new( @@ -57,25 +57,25 @@ impl RedisCalendarService { format!("Failed to serialize event: {}", e), )) })?; - + // Save the event - let event_key = format!("{}{}", Self::EVENT_KEY_PREFIX, event.id); + let event_key = format!("{}{}", Self::EVENT_KEY_PREFIX, event.base_data.id); let _: () = conn.set(event_key, json)?; - + // Add the event ID to the set of all events - let _: () = conn.sadd(Self::ALL_EVENTS_KEY, &event.id)?; - + let _: () = conn.sadd(Self::ALL_EVENTS_KEY, &event.base_data.id)?; + Ok(()) } - + /// Get a calendar event from Redis by ID pub fn get_event(id: &str) -> Result, RedisError> { let mut conn = get_connection()?; - + // Get the event JSON let event_key = format!("{}{}", Self::EVENT_KEY_PREFIX, id); let json: Option = conn.get(event_key)?; - + // Parse the JSON if let Some(json) = json { let event = CalendarEvent::from_json(&json).map_err(|e| { @@ -84,34 +84,34 @@ impl RedisCalendarService { format!("Failed to deserialize event: {}", e), )) })?; - + Ok(Some(event)) } else { Ok(None) } } - + /// Delete a calendar event from Redis pub fn delete_event(id: &str) -> Result { let mut conn = get_connection()?; - + // Delete the event let event_key = format!("{}{}", Self::EVENT_KEY_PREFIX, id); let deleted: i32 = conn.del(event_key)?; - + // Remove the event ID from the set of all events let _: () = conn.srem(Self::ALL_EVENTS_KEY, id)?; - + Ok(deleted > 0) } - + /// Get all calendar events from Redis pub fn get_all_events() -> Result, RedisError> { let mut conn = get_connection()?; - + // Get all event IDs let event_ids: Vec = conn.smembers(Self::ALL_EVENTS_KEY)?; - + // Get all events let mut events = Vec::new(); for id in event_ids { @@ -119,23 +119,23 @@ impl RedisCalendarService { events.push(event); } } - + Ok(events) } - + /// Get events for a specific date range pub fn get_events_in_range( start: chrono::DateTime, end: chrono::DateTime, ) -> Result, RedisError> { let all_events = Self::get_all_events()?; - + // Filter events that fall within the date range let filtered_events = all_events .into_iter() .filter(|event| event.start_time <= end && event.end_time >= start) .collect(); - + Ok(filtered_events) } -} \ No newline at end of file +} diff --git a/actix_mvc_app/src/views/calendar/index.html b/actix_mvc_app/src/views/calendar/index.html index 0b28aea..4fe1f1f 100644 --- a/actix_mvc_app/src/views/calendar/index.html +++ b/actix_mvc_app/src/views/calendar/index.html @@ -114,8 +114,9 @@ {% for event in day.events %}
+ onclick="openEventDetails(event, '{{ event.base_data.id }}', '{{ event.title|escape }}', '{{ event.description|escape }}', '{{ event.color }}', {{ event.all_day }}, '{{ event.start_time }}', '{{ event.end_time }}')">
{{ event.title }}
{% if event.description %}

{{ event.description }}

@@ -235,7 +236,7 @@ {% set start_hour = event.start_time|extract_hour %} {% if start_hour == hour %}
+ onclick="openEventDetails(event, '{{ event.base_data.id }}', '{{ event.title|escape }}', '{{ event.description|escape }}', '{{ event.color }}', {{ event.all_day }}, '{{ event.start_time }}', '{{ event.end_time }}')">
{{ event.title }}

{{ event.start_time|format_time }} - {{ event.end_time|format_time }}

{{ event.description }}

@@ -859,7 +860,7 @@ eventDiv.onclick = (e) => { e.stopPropagation(); closeEventsPopup(); - openEventDetails(e, event.id, event.title, event.description, event.color, event.all_day, event.start_time, event.end_time); + openEventDetails(e, event.base_data.id, event.title, event.description, event.color, event.all_day, event.start_time, event.end_time); }; content.appendChild(eventDiv); });