Add issue creation and editing
This commit is contained in:
@@ -139,6 +139,20 @@ pub struct IssueDetails {
|
||||
pub comments: Vec<models::Comment>,
|
||||
}
|
||||
|
||||
pub struct IssueEditorData {
|
||||
pub issue: Option<models::Issue>,
|
||||
pub labels: Vec<models::Label>,
|
||||
pub milestones: Vec<models::Milestone>,
|
||||
}
|
||||
|
||||
pub struct IssueDraft {
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
pub label_ids: Vec<i64>,
|
||||
pub milestone_id: Option<i64>,
|
||||
pub due_date: Option<i64>,
|
||||
}
|
||||
|
||||
pub struct MilestoneDetails {
|
||||
pub milestone: models::Milestone,
|
||||
pub issues: Vec<models::Issue>,
|
||||
@@ -155,6 +169,49 @@ pub fn open_status() -> String {
|
||||
"open".into()
|
||||
}
|
||||
|
||||
pub fn civil_from_days(days: i64) -> (i64, i64, i64) {
|
||||
let days = days + 719_468;
|
||||
let era = days.div_euclid(146_097);
|
||||
let day_of_era = days - era * 146_097;
|
||||
let year_of_era =
|
||||
(day_of_era - day_of_era / 1_460 + day_of_era / 36_524 - day_of_era / 146_096) / 365;
|
||||
let mut year = year_of_era + era * 400;
|
||||
let day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
|
||||
let month_prime = (5 * day_of_year + 2) / 153;
|
||||
let day = day_of_year - (153 * month_prime + 2) / 5 + 1;
|
||||
let month = month_prime + if month_prime < 10 { 3 } else { -9 };
|
||||
year += i64::from(month <= 2);
|
||||
(year, month, day)
|
||||
}
|
||||
|
||||
pub fn days_from_civil(mut year: i64, month: i64, day: i64) -> i64 {
|
||||
year -= i64::from(month <= 2);
|
||||
let era = year.div_euclid(400);
|
||||
let year_of_era = year - era * 400;
|
||||
let month_prime = month + if month > 2 { -3 } else { 9 };
|
||||
let day_of_year = (153 * month_prime + 2) / 5 + day - 1;
|
||||
let day_of_era = year_of_era * 365 + year_of_era / 4 - year_of_era / 100 + day_of_year;
|
||||
era * 146_097 + day_of_era - 719_468
|
||||
}
|
||||
|
||||
pub fn api_date(timestamp: i64) -> String {
|
||||
let (year, month, day) = civil_from_days(timestamp.div_euclid(86_400));
|
||||
format!("{year:04}-{month:02}-{day:02}T00:00:00Z")
|
||||
}
|
||||
|
||||
pub fn parse_api_date(value: &str) -> Option<i64> {
|
||||
let date = value.get(..10)?;
|
||||
let mut parts = date.split('-');
|
||||
let year = parts.next()?.parse().ok()?;
|
||||
let month = parts.next()?.parse().ok()?;
|
||||
let day = parts.next()?.parse().ok()?;
|
||||
if parts.next().is_some() || !(1..=12).contains(&month) || !(1..=31).contains(&day) {
|
||||
return None;
|
||||
}
|
||||
let days = days_from_civil(year, month, day);
|
||||
(civil_from_days(days) == (year, month, day)).then_some(days * 86_400)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -179,4 +236,12 @@ mod tests {
|
||||
.is_active("open")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_dates_round_trip_and_reject_invalid_dates() {
|
||||
let leap_day = parse_api_date("2024-02-29T12:34:56Z").unwrap();
|
||||
assert_eq!(api_date(leap_day), "2024-02-29T00:00:00Z");
|
||||
assert_eq!(parse_api_date("2023-02-29T00:00:00Z"), None);
|
||||
assert_eq!(parse_api_date("not-a-date"), None);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user