2024-01-01 13:47:23 +01:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2022-08-16 17:56:24 +02:00
|
|
|
use chrono::TimeZone;
|
2022-08-16 10:32:46 +02:00
|
|
|
use ics::{
|
2024-01-30 20:21:21 +01:00
|
|
|
parameters::{Language, PartStat, Role, TzIDParam, CN},
|
2024-01-30 14:09:17 +01:00
|
|
|
properties::{
|
2024-01-30 15:21:42 +01:00
|
|
|
Attendee, Categories, Class, Description, DtEnd, DtStart, Location, Summary, Transp,
|
2024-01-30 14:09:17 +01:00
|
|
|
},
|
2022-08-16 17:56:24 +02:00
|
|
|
Event, ICalendar, Standard,
|
2022-08-16 10:32:46 +02:00
|
|
|
};
|
|
|
|
|
2023-04-23 00:22:19 +02:00
|
|
|
pub fn export(courses: Vec<crate::timetable::models::Course>, filename: &mut String) {
|
2024-01-23 10:07:37 +01:00
|
|
|
let mut calendar = ICalendar::new("2.0", "cal7tor");
|
2022-08-16 10:32:46 +02:00
|
|
|
|
2022-08-16 17:56:24 +02:00
|
|
|
// Add Europe/Paris timezone
|
|
|
|
let timezone_name = "Europe/Paris";
|
|
|
|
calendar.add_timezone(ics::TimeZone::standard(
|
|
|
|
timezone_name,
|
|
|
|
Standard::new(
|
2022-08-18 12:37:40 +02:00
|
|
|
// Add a Z because it's UTC
|
2023-01-10 12:01:45 +01:00
|
|
|
dt_ical(chrono::Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()) + "Z",
|
2022-08-16 17:56:24 +02:00
|
|
|
"+0100",
|
|
|
|
"+0200",
|
|
|
|
),
|
|
|
|
));
|
|
|
|
|
2022-08-16 11:54:47 +02:00
|
|
|
// Create events which contains the information regarding the course
|
|
|
|
for course in courses {
|
2022-08-16 14:40:55 +02:00
|
|
|
let mut event = Event::new(
|
|
|
|
uuid::Uuid::new_v4().to_string(),
|
2022-08-18 12:37:40 +02:00
|
|
|
// Add a Z because it's UTC
|
|
|
|
dt_ical(chrono::Utc::now()) + "Z",
|
2022-08-16 14:40:55 +02:00
|
|
|
);
|
2022-08-16 10:32:46 +02:00
|
|
|
|
2022-08-16 11:54:47 +02:00
|
|
|
// Public event
|
|
|
|
event.push(Class::public());
|
2022-08-16 14:22:04 +02:00
|
|
|
|
2022-08-16 11:54:47 +02:00
|
|
|
// Consume actual time
|
|
|
|
event.push(Transp::opaque());
|
2022-08-16 14:22:04 +02:00
|
|
|
|
2022-08-16 11:54:47 +02:00
|
|
|
// Professor's name
|
2022-08-16 14:06:58 +02:00
|
|
|
if course.professor.is_some() {
|
2024-01-30 20:21:21 +01:00
|
|
|
let name = course.professor.unwrap();
|
|
|
|
let mut contact = Attendee::new(format!("mailto:{name}"));
|
|
|
|
contact.add(CN::new(name));
|
|
|
|
contact.add(PartStat::ACCEPTED);
|
|
|
|
contact.add(Role::CHAIR);
|
|
|
|
event.push(contact);
|
2022-08-16 14:06:58 +02:00
|
|
|
}
|
2022-08-16 14:22:04 +02:00
|
|
|
|
2022-08-16 11:54:47 +02:00
|
|
|
// Start time of the course
|
2022-08-16 17:56:24 +02:00
|
|
|
let mut date_start = DtStart::new(dt_ical(course.dtstart.unwrap()));
|
2024-01-30 15:19:00 +01:00
|
|
|
date_start.add(TzIDParam::new(timezone_name));
|
2022-08-16 17:56:24 +02:00
|
|
|
event.push(date_start);
|
2022-08-16 14:22:04 +02:00
|
|
|
|
2022-08-16 11:54:47 +02:00
|
|
|
// End time of the course
|
2022-08-16 17:56:24 +02:00
|
|
|
let mut date_end = DtEnd::new(dt_ical(course.dtend.unwrap()));
|
2024-01-30 15:19:00 +01:00
|
|
|
date_end.add(TzIDParam::new(timezone_name));
|
2022-08-16 17:56:24 +02:00
|
|
|
event.push(date_end);
|
2022-08-16 14:22:04 +02:00
|
|
|
|
2022-08-16 11:54:47 +02:00
|
|
|
// Room location
|
|
|
|
event.push(Location::new(course.room));
|
2022-08-16 14:22:04 +02:00
|
|
|
|
2024-01-01 13:47:23 +01:00
|
|
|
let categories = course
|
|
|
|
.category
|
|
|
|
.iter()
|
|
|
|
.map(|c| c.to_string())
|
|
|
|
.collect::<Arc<[String]>>()
|
|
|
|
.join("/");
|
|
|
|
|
2022-08-16 11:54:47 +02:00
|
|
|
// Course's name
|
2024-01-01 13:47:23 +01:00
|
|
|
let mut course_name = Summary::new(format!("{} - {}", categories, course.name));
|
2024-01-30 15:19:00 +01:00
|
|
|
course_name.add(Language::new("fr"));
|
2022-08-18 12:37:40 +02:00
|
|
|
event.push(course_name);
|
2022-08-16 10:32:46 +02:00
|
|
|
|
2023-10-02 14:53:40 +02:00
|
|
|
// Course's category
|
2024-01-01 13:47:23 +01:00
|
|
|
event.push(Categories::new(categories));
|
2023-10-02 14:47:31 +02:00
|
|
|
|
2024-01-30 14:09:17 +01:00
|
|
|
// Course extra data
|
|
|
|
if course.data.is_some() {
|
2024-01-30 15:21:42 +01:00
|
|
|
event.push(Description::new(course.data.unwrap()));
|
2024-01-30 14:09:17 +01:00
|
|
|
}
|
|
|
|
|
2022-08-16 11:54:47 +02:00
|
|
|
// Add the course to the calendar
|
|
|
|
calendar.add_event(event);
|
|
|
|
}
|
2022-08-16 10:32:46 +02:00
|
|
|
|
2023-04-23 00:22:19 +02:00
|
|
|
// Add the extension if needed
|
|
|
|
if !filename.ends_with(".ics") {
|
|
|
|
*filename = format!("{}.ics", filename)
|
|
|
|
};
|
|
|
|
|
|
|
|
calendar.save_file(filename).unwrap();
|
2022-08-16 10:32:46 +02:00
|
|
|
}
|
2022-08-16 11:54:47 +02:00
|
|
|
|
|
|
|
/// Transform the datetime from chrono to the ICS format
|
2022-08-16 12:16:23 +02:00
|
|
|
/// See <https://github.com/hummingly/ics/issues/17#issue-985662287>
|
2022-08-16 11:54:47 +02:00
|
|
|
fn dt_ical(dt: chrono::DateTime<chrono::Utc>) -> String {
|
2022-08-16 17:56:24 +02:00
|
|
|
format!("{}", dt.format("%Y%m%dT%H%M%S"))
|
2022-08-16 11:54:47 +02:00
|
|
|
}
|