fmt, fixes and additions

This commit is contained in:
timurgordon
2025-06-19 13:18:10 +03:00
parent 6b3cbfc4b2
commit e91a44ce37
86 changed files with 5292 additions and 2844 deletions

View File

@@ -1,24 +1,24 @@
use rhai::plugin::*;
use rhai::{Engine, EvalAltResult, Position, Module, INT, Dynamic, Array};
use std::sync::Arc;
use std::mem;
use crate::db::Db;
use rhai::plugin::*;
use rhai::{Array, Dynamic, Engine, EvalAltResult, INT, Module, Position};
use std::mem;
use std::sync::Arc;
use super::calendar::{Event, Attendee, Calendar, AttendanceStatus};
use super::calendar::{AttendanceStatus, Attendee, Calendar, Event};
type RhaiEvent = Event;
type RhaiAttendee = Attendee;
type RhaiCalendar = Calendar;
use crate::db::hero::OurDB;
use crate::db::Collection;
use crate::db::hero::OurDB;
// Helper to convert i64 from Rhai to u32 for IDs
fn id_from_i64_to_u32(id_i64: i64) -> Result<u32, Box<EvalAltResult>> {
u32::try_from(id_i64).map_err(|_|
u32::try_from(id_i64).map_err(|_| {
Box::new(EvalAltResult::ErrorArithmetic(
format!("Failed to convert ID '{}' to u32", id_i64).into(),
Position::NONE
Position::NONE,
))
)
})
}
#[export_module]
@@ -28,26 +28,35 @@ mod rhai_calendar_module {
pub fn new_event() -> RhaiEvent {
Event::new()
}
/// Sets the event title
#[rhai_fn(name = "title", return_raw, global, pure)]
pub fn event_title(event: &mut RhaiEvent, title: String) -> Result<RhaiEvent, Box<EvalAltResult>> {
pub fn event_title(
event: &mut RhaiEvent,
title: String,
) -> Result<RhaiEvent, Box<EvalAltResult>> {
let owned_event = mem::take(event);
*event = owned_event.title(title);
Ok(event.clone())
}
/// Sets the event description
#[rhai_fn(name = "description", return_raw, global, pure)]
pub fn event_description(event: &mut RhaiEvent, description: String) -> Result<RhaiEvent, Box<EvalAltResult>> {
pub fn event_description(
event: &mut RhaiEvent,
description: String,
) -> Result<RhaiEvent, Box<EvalAltResult>> {
let owned_event = mem::take(event);
*event = owned_event.description(description);
Ok(event.clone())
}
/// Sets the event location
#[rhai_fn(name = "location", return_raw, global, pure)]
pub fn event_location(event: &mut RhaiEvent, location: String) -> Result<RhaiEvent, Box<EvalAltResult>> {
pub fn event_location(
event: &mut RhaiEvent,
location: String,
) -> Result<RhaiEvent, Box<EvalAltResult>> {
let owned_event = mem::take(event);
*event = owned_event.location(location);
Ok(event.clone())
@@ -55,7 +64,10 @@ mod rhai_calendar_module {
/// Adds an attendee to the event
#[rhai_fn(name = "add_attendee", return_raw, global, pure)]
pub fn event_add_attendee(event: &mut RhaiEvent, attendee: RhaiAttendee) -> Result<RhaiEvent, Box<EvalAltResult>> {
pub fn event_add_attendee(
event: &mut RhaiEvent,
attendee: RhaiAttendee,
) -> Result<RhaiEvent, Box<EvalAltResult>> {
// Use take to get ownership of the event
let owned_event = mem::take(event);
*event = owned_event.add_attendee(attendee);
@@ -64,30 +76,38 @@ mod rhai_calendar_module {
/// Reschedules the event with new start and end times
#[rhai_fn(name = "reschedule", return_raw, global, pure)]
pub fn event_reschedule(event: &mut RhaiEvent, new_start_time: i64, new_end_time: i64) -> Result<RhaiEvent, Box<EvalAltResult>> {
pub fn event_reschedule(
event: &mut RhaiEvent,
new_start_time: i64,
new_end_time: i64,
) -> Result<RhaiEvent, Box<EvalAltResult>> {
// Validate timestamps
if new_end_time <= new_start_time {
return Err(Box::new(EvalAltResult::ErrorRuntime(
"End time must be after start time".into(),
Position::NONE
Position::NONE,
)));
}
// Use take to get ownership of the event
let owned_event = mem::take(event);
*event = owned_event.reschedule(new_start_time, new_end_time);
Ok(event.clone())
}
/// Updates an attendee's status in the event
#[rhai_fn(name = "update_attendee_status", return_raw, global, pure)]
pub fn event_update_attendee_status(event: &mut RhaiEvent, contact_id: i64, status_str: String) -> Result<RhaiEvent, Box<EvalAltResult>> {
pub fn event_update_attendee_status(
event: &mut RhaiEvent,
contact_id: i64,
status_str: String,
) -> Result<RhaiEvent, Box<EvalAltResult>> {
let status_enum = AttendanceStatus::from_string(&status_str)
.map_err(|_| Box::new(EvalAltResult::ErrorRuntime(
format!("Invalid attendance status: '{}'. Expected one of: Pending, Accepted, Declined, Tentative", status_str).into(),
Position::NONE
)))?;
// Use take to get ownership of the event
let owned_event = mem::take(event);
*event = owned_event.update_attendee_status(id_from_i64_to_u32(contact_id)?, status_enum);
@@ -96,50 +116,74 @@ mod rhai_calendar_module {
// Event Getters
#[rhai_fn(get = "id", pure)]
pub fn get_event_id(event: &mut RhaiEvent) -> i64 { event.base_data.id as i64 }
pub fn get_event_id(event: &mut RhaiEvent) -> i64 {
event.base_data.id as i64
}
#[rhai_fn(get = "created_at", pure)]
pub fn get_event_created_at(event: &mut RhaiEvent) -> i64 { event.base_data.created_at }
pub fn get_event_created_at(event: &mut RhaiEvent) -> i64 {
event.base_data.created_at
}
#[rhai_fn(get = "modified_at", pure)]
pub fn get_event_modified_at(event: &mut RhaiEvent) -> i64 { event.base_data.modified_at }
pub fn get_event_modified_at(event: &mut RhaiEvent) -> i64 {
event.base_data.modified_at
}
#[rhai_fn(get = "title", pure)]
pub fn get_event_title(event: &mut RhaiEvent) -> String { event.title.clone() }
pub fn get_event_title(event: &mut RhaiEvent) -> String {
event.title.clone()
}
#[rhai_fn(get = "description", pure)]
pub fn get_event_description(event: &mut RhaiEvent) -> Option<String> { event.description.clone() }
pub fn get_event_description(event: &mut RhaiEvent) -> Option<String> {
event.description.clone()
}
#[rhai_fn(get = "start_time", pure)]
pub fn get_event_start_time(event: &mut RhaiEvent) -> i64 { event.start_time }
pub fn get_event_start_time(event: &mut RhaiEvent) -> i64 {
event.start_time
}
#[rhai_fn(get = "end_time", pure)]
pub fn get_event_end_time(event: &mut RhaiEvent) -> i64 { event.end_time }
pub fn get_event_end_time(event: &mut RhaiEvent) -> i64 {
event.end_time
}
#[rhai_fn(get = "location", pure)]
pub fn get_event_location(event: &mut RhaiEvent) -> Option<String> { event.location.clone() }
pub fn get_event_location(event: &mut RhaiEvent) -> Option<String> {
event.location.clone()
}
#[rhai_fn(get = "attendees", pure)]
pub fn get_event_attendees(event: &mut RhaiEvent) -> Vec<RhaiAttendee> { event.attendees.clone() }
pub fn get_event_attendees(event: &mut RhaiEvent) -> Vec<RhaiAttendee> {
event.attendees.clone()
}
// --- Attendee Functions ---
#[rhai_fn(name = "new_attendee")]
pub fn new_attendee() -> RhaiAttendee {
Attendee::new(0) // Default contact_id, will be set via builder
}
/// Sets the contact ID for an attendee
#[rhai_fn(name = "with_contact_id", return_raw, global, pure)]
pub fn attendee_with_contact_id(attendee: &mut RhaiAttendee, contact_id: i64) -> Result<RhaiAttendee, Box<EvalAltResult>> {
pub fn attendee_with_contact_id(
attendee: &mut RhaiAttendee,
contact_id: i64,
) -> Result<RhaiAttendee, Box<EvalAltResult>> {
let new_contact_id = id_from_i64_to_u32(contact_id).unwrap_or(0);
let owned_attendee = mem::replace(attendee, Attendee::new(0));
*attendee = Attendee::new(new_contact_id);
attendee.status = owned_attendee.status;
Ok(attendee.clone())
}
/// Sets the status for an attendee
#[rhai_fn(name = "with_status", return_raw, global, pure)]
pub fn attendee_with_status(attendee: &mut RhaiAttendee, status_str: String) -> Result<RhaiAttendee, Box<EvalAltResult>> {
pub fn attendee_with_status(
attendee: &mut RhaiAttendee,
status_str: String,
) -> Result<RhaiAttendee, Box<EvalAltResult>> {
let status_enum = AttendanceStatus::from_string(&status_str)
.map_err(|_| Box::new(EvalAltResult::ErrorRuntime(
format!("Invalid attendance status: '{}'. Expected one of: Accepted, Declined, Tentative, NoResponse", status_str).into(),
Position::NONE
)))?;
let owned_attendee = mem::replace(attendee, Attendee::new(0));
*attendee = owned_attendee.status(status_enum);
Ok(attendee.clone())
@@ -149,9 +193,13 @@ mod rhai_calendar_module {
// Attendee Getters
#[rhai_fn(get = "contact_id", pure)]
pub fn get_attendee_contact_id(attendee: &mut RhaiAttendee) -> i64 { attendee.contact_id as i64 }
pub fn get_attendee_contact_id(attendee: &mut RhaiAttendee) -> i64 {
attendee.contact_id as i64
}
#[rhai_fn(get = "status", pure)]
pub fn get_attendee_status(attendee: &mut RhaiAttendee) -> String { attendee.status.to_string() }
pub fn get_attendee_status(attendee: &mut RhaiAttendee) -> String {
attendee.status.to_string()
}
// --- Calendar Functions ---
#[rhai_fn(name = "new_calendar", return_raw)]
@@ -159,25 +207,31 @@ mod rhai_calendar_module {
let calendar = Calendar::new(None, "");
Ok(calendar)
}
/// Sets the calendar name
#[rhai_fn(name = "name", return_raw, global, pure)]
pub fn calendar_name(calendar: &mut RhaiCalendar, name: String) -> Result<RhaiCalendar, Box<EvalAltResult>> {
pub fn calendar_name(
calendar: &mut RhaiCalendar,
name: String,
) -> Result<RhaiCalendar, Box<EvalAltResult>> {
// Create a default Calendar to replace the taken one
let default_calendar = Calendar::new(None, "");
// Take ownership of the calendar, apply the builder method, then put it back
let owned_calendar = std::mem::replace(calendar, default_calendar);
*calendar = Calendar::new(Some(owned_calendar.base_data.id), name);
Ok(calendar.clone())
}
/// Sets the calendar description
#[rhai_fn(name = "description", return_raw, global, pure)]
pub fn calendar_description(calendar: &mut RhaiCalendar, description: String) -> Result<RhaiCalendar, Box<EvalAltResult>> {
pub fn calendar_description(
calendar: &mut RhaiCalendar,
description: String,
) -> Result<RhaiCalendar, Box<EvalAltResult>> {
// Create a default Calendar to replace the taken one
let default_calendar = Calendar::new(None, "");
// Take ownership of the calendar, apply the builder method, then put it back
let owned_calendar = std::mem::replace(calendar, default_calendar);
let updated_calendar = owned_calendar.description(description);
@@ -186,10 +240,13 @@ mod rhai_calendar_module {
}
#[rhai_fn(name = "add_event_to_calendar", return_raw, global, pure)]
pub fn calendar_add_event(calendar: &mut RhaiCalendar, event: RhaiEvent) -> Result<RhaiCalendar, Box<EvalAltResult>> {
pub fn calendar_add_event(
calendar: &mut RhaiCalendar,
event: RhaiEvent,
) -> Result<RhaiCalendar, Box<EvalAltResult>> {
// Create a default Calendar to replace the taken one
let default_calendar = Calendar::new(None, "");
// Take ownership of the calendar, apply the builder method, then put it back
let owned_calendar = std::mem::replace(calendar, default_calendar);
*calendar = owned_calendar.add_event(event.base_data.id as i64);
@@ -197,10 +254,13 @@ mod rhai_calendar_module {
}
#[rhai_fn(name = "remove_event_from_calendar", return_raw)]
pub fn calendar_remove_event(calendar: &mut RhaiCalendar, event_id: i64) -> Result<(), Box<EvalAltResult>> {
pub fn calendar_remove_event(
calendar: &mut RhaiCalendar,
event_id: i64,
) -> Result<(), Box<EvalAltResult>> {
// Create a default Calendar to replace the taken one
let default_calendar = Calendar::new(None, "");
// Take ownership of the calendar, apply the builder method, then put it back
let owned_calendar = std::mem::replace(calendar, default_calendar);
*calendar = owned_calendar.remove_event(id_from_i64_to_u32(event_id)? as i64);
@@ -209,140 +269,213 @@ mod rhai_calendar_module {
// Calendar Getters
#[rhai_fn(get = "id", pure)]
pub fn get_calendar_id(calendar: &mut RhaiCalendar) -> i64 { calendar.base_data.id as i64 }
pub fn get_calendar_id(calendar: &mut RhaiCalendar) -> i64 {
calendar.base_data.id as i64
}
#[rhai_fn(get = "name", pure)]
pub fn get_calendar_name(calendar: &mut RhaiCalendar) -> String { calendar.name.clone() }
pub fn get_calendar_name(calendar: &mut RhaiCalendar) -> String {
calendar.name.clone()
}
#[rhai_fn(get = "created_at", pure)]
pub fn get_calendar_created_at(calendar: &mut RhaiCalendar) -> i64 { calendar.base_data.created_at }
pub fn get_calendar_created_at(calendar: &mut RhaiCalendar) -> i64 {
calendar.base_data.created_at
}
#[rhai_fn(get = "modified_at", pure)]
pub fn get_calendar_modified_at(calendar: &mut RhaiCalendar) -> i64 { calendar.base_data.modified_at }
pub fn get_calendar_modified_at(calendar: &mut RhaiCalendar) -> i64 {
calendar.base_data.modified_at
}
#[rhai_fn(get = "events", pure)]
pub fn get_calendar_events(calendar: &mut RhaiCalendar) -> Vec<i64> { calendar.events.clone() }
pub fn get_calendar_events(calendar: &mut RhaiCalendar) -> Vec<i64> {
calendar.events.clone()
}
#[rhai_fn(get = "description", pure)]
pub fn get_calendar_description(calendar: &mut RhaiCalendar) -> Option<String> { calendar.description.clone() }
pub fn get_calendar_description(calendar: &mut RhaiCalendar) -> Option<String> {
calendar.description.clone()
}
// Calendar doesn't have an owner_id field in the current implementation
// pub fn get_calendar_owner_id(calendar: &mut RhaiCalendar) -> i64 { calendar.owner_id as i64 }
}
pub fn register_calendar_rhai_module(engine: &mut Engine, db: Arc<OurDB>) {
// Register the exported module globally
let module = exported_module!(rhai_calendar_module);
engine.register_global_module(module.into());
// Create a module for database functions
let mut db_module = Module::new();
// Manually register database functions as they need to capture 'db'
let db_clone_set_event = db.clone();
db_module.set_native_fn("save_event", move |event: Event| -> Result<Event, Box<EvalAltResult>> {
// Use the Collection trait method directly
let result = db_clone_set_event.set(&event)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error set_event: {}", e).into(), Position::NONE)))?;
// Return the updated event with the correct ID
Ok(result.1)
});
db_module.set_native_fn(
"save_event",
move |event: Event| -> Result<Event, Box<EvalAltResult>> {
// Use the Collection trait method directly
let result = db_clone_set_event.set(&event).map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("DB Error set_event: {}", e).into(),
Position::NONE,
))
})?;
// Return the updated event with the correct ID
Ok(result.1)
},
);
// Manually register database functions as they need to capture 'db'
let db_clone_delete_event = db.clone();
db_module.set_native_fn("delete_event", move |event: Event| -> Result<(), Box<EvalAltResult>> {
// Use the Collection trait method directly
let result = db_clone_delete_event.collection::<Event>()
.expect("can open event collection")
.delete_by_id(event.base_data.id)
.expect("can delete event");
// Return the updated event with the correct ID
Ok(result)
});
db_module.set_native_fn(
"delete_event",
move |event: Event| -> Result<(), Box<EvalAltResult>> {
// Use the Collection trait method directly
let result = db_clone_delete_event
.collection::<Event>()
.expect("can open event collection")
.delete_by_id(event.base_data.id)
.expect("can delete event");
// Return the updated event with the correct ID
Ok(result)
},
);
let db_clone_get_event = db.clone();
db_module.set_native_fn("get_event_by_id", move |id_i64: INT| -> Result<Event, Box<EvalAltResult>> {
let id_u32 = id_from_i64_to_u32(id_i64)?;
// Use the Collection trait method directly
db_clone_get_event.get_by_id(id_u32)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_event_by_id: {}", e).into(), Position::NONE)))?
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("Event with ID {} not found", id_u32).into(), Position::NONE)))
});
db_module.set_native_fn(
"get_event_by_id",
move |id_i64: INT| -> Result<Event, Box<EvalAltResult>> {
let id_u32 = id_from_i64_to_u32(id_i64)?;
// Use the Collection trait method directly
db_clone_get_event
.get_by_id(id_u32)
.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("DB Error get_event_by_id: {}", e).into(),
Position::NONE,
))
})?
.ok_or_else(|| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Event with ID {} not found", id_u32).into(),
Position::NONE,
))
})
},
);
let db_clone_set_calendar = db.clone();
db_module.set_native_fn("save_calendar", move |calendar: Calendar| -> Result<Calendar, Box<EvalAltResult>> {
// Use the Collection trait method directly
let result = db_clone_set_calendar.set(&calendar)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error set_calendar: {}", e).into(), Position::NONE)))?;
// Return the updated calendar with the correct ID
Ok(result.1)
});
db_module.set_native_fn(
"save_calendar",
move |calendar: Calendar| -> Result<Calendar, Box<EvalAltResult>> {
// Use the Collection trait method directly
let result = db_clone_set_calendar.set(&calendar).map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("DB Error set_calendar: {}", e).into(),
Position::NONE,
))
})?;
// Return the updated calendar with the correct ID
Ok(result.1)
},
);
// Manually register database functions as they need to capture 'db'
let db_clone_delete_calendar = db.clone();
db_module.set_native_fn("delete_calendar", move |calendar: Calendar| -> Result<(), Box<EvalAltResult>> {
// Use the Collection trait method directly
let result = db_clone_delete_calendar.collection::<Calendar>()
.expect("can open calendar collection")
.delete_by_id(calendar.base_data.id)
.expect("can delete event");
// Return the updated event with the correct ID
Ok(result)
});
db_module.set_native_fn(
"delete_calendar",
move |calendar: Calendar| -> Result<(), Box<EvalAltResult>> {
// Use the Collection trait method directly
let result = db_clone_delete_calendar
.collection::<Calendar>()
.expect("can open calendar collection")
.delete_by_id(calendar.base_data.id)
.expect("can delete event");
// Return the updated event with the correct ID
Ok(result)
},
);
let db_clone_get_calendar = db.clone();
db_module.set_native_fn("get_calendar_by_id", move |id_i64: INT| -> Result<Calendar, Box<EvalAltResult>> {
let id_u32 = id_from_i64_to_u32(id_i64)?;
// Use the Collection trait method directly
db_clone_get_calendar.get_by_id(id_u32)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_calendar_by_id: {}", e).into(), Position::NONE)))?
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("Calendar with ID {} not found", id_u32).into(), Position::NONE)))
});
db_module.set_native_fn(
"get_calendar_by_id",
move |id_i64: INT| -> Result<Calendar, Box<EvalAltResult>> {
let id_u32 = id_from_i64_to_u32(id_i64)?;
// Use the Collection trait method directly
db_clone_get_calendar
.get_by_id(id_u32)
.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("DB Error get_calendar_by_id: {}", e).into(),
Position::NONE,
))
})?
.ok_or_else(|| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Calendar with ID {} not found", id_u32).into(),
Position::NONE,
))
})
},
);
// Add list_calendars function to get all calendars
let db_clone_list_calendars = db.clone();
db_module.set_native_fn("list_calendars", move || -> Result<Dynamic, Box<EvalAltResult>> {
let collection = db_clone_list_calendars.collection::<Calendar>()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get calendar collection: {:?}", e).into(),
Position::NONE
)))?;
let calendars = collection.get_all()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get all calendars: {:?}", e).into(),
Position::NONE
)))?;
let mut array = Array::new();
for calendar in calendars {
array.push(Dynamic::from(calendar));
}
Ok(Dynamic::from(array))
});
db_module.set_native_fn(
"list_calendars",
move || -> Result<Dynamic, Box<EvalAltResult>> {
let collection = db_clone_list_calendars
.collection::<Calendar>()
.map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get calendar collection: {:?}", e).into(),
Position::NONE,
))
})?;
let calendars = collection.get_all().map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get all calendars: {:?}", e).into(),
Position::NONE,
))
})?;
let mut array = Array::new();
for calendar in calendars {
array.push(Dynamic::from(calendar));
}
Ok(Dynamic::from(array))
},
);
// Add list_events function to get all events
let db_clone_list_events = db.clone();
db_module.set_native_fn("list_events", move || -> Result<Dynamic, Box<EvalAltResult>> {
let collection = db_clone_list_events.collection::<Event>()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get event collection: {:?}", e).into(),
Position::NONE
)))?;
let events = collection.get_all()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get all events: {:?}", e).into(),
Position::NONE
)))?;
let mut array = Array::new();
for event in events {
array.push(Dynamic::from(event));
}
Ok(Dynamic::from(array))
});
db_module.set_native_fn(
"list_events",
move || -> Result<Dynamic, Box<EvalAltResult>> {
let collection = db_clone_list_events.collection::<Event>().map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get event collection: {:?}", e).into(),
Position::NONE,
))
})?;
let events = collection.get_all().map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get all events: {:?}", e).into(),
Position::NONE,
))
})?;
let mut array = Array::new();
for event in events {
array.push(Dynamic::from(event));
}
Ok(Dynamic::from(array))
},
);
// Register the database module globally
engine.register_global_module(db_module.into());