use std::error::Error; use serde::Deserialize; use time::{macros::format_description, PrimitiveDateTime}; #[derive(Debug, Clone, PartialEq, Deserialize)] #[non_exhaustive] pub struct Notification { pub id: String, pub repository: Repository, pub subject: Subject, pub reason: String, pub unread: bool, pub updated_at: String, pub last_read_at: Option, pub url: String, } #[derive(Debug, Clone, Eq, PartialEq, Deserialize)] #[non_exhaustive] pub struct Repository { pub id: u64, pub node_id: Option, pub name: String, pub full_name: Option, pub owner: Option, pub private: Option, pub html_url: Option, pub description: Option, pub fork: Option, pub url: String, pub archive_url: Option, pub assignees_url: Option, pub blobs_url: Option, pub branches_url: Option, pub collaborators_url: Option, pub comments_url: Option, pub commits_url: Option, pub compare_url: Option, pub contents_url: Option, pub contributors_url: Option, pub deployments_url: Option, pub downloads_url: Option, pub events_url: Option, pub forks_url: Option, pub git_commits_url: Option, pub git_refs_url: Option, pub git_tags_url: Option, pub git_url: Option, pub issue_comment_url: Option, pub issue_events_url: Option, pub issues_url: Option, pub keys_url: Option, pub labels_url: Option, pub languages_url: Option, pub merges_url: Option, pub milestones_url: Option, pub notifications_url: Option, pub pulls_url: Option, pub releases_url: Option, pub ssh_url: Option, pub stargazers_url: Option, pub statuses_url: Option, pub subscribers_url: Option, pub subscription_url: Option, pub tags_url: Option, pub teams_url: Option, pub trees_url: Option, pub clone_url: Option, pub mirror_url: Option, pub hooks_url: Option, pub svn_url: Option, pub homepage: Option, pub language: Option<::serde_json::Value>, pub forks_count: Option, pub stargazers_count: Option, pub watchers_count: Option, pub size: Option, pub default_branch: Option, pub open_issues_count: Option, pub is_template: Option, pub topics: Option>, pub has_issues: Option, pub has_projects: Option, pub has_wiki: Option, pub has_pages: Option, pub has_downloads: Option, pub archived: Option, pub disabled: Option, pub visibility: Option, pub pushed_at: Option, pub created_at: Option, pub updated_at: Option, pub permissions: Option, pub allow_rebase_merge: Option, pub template_repository: Option>, pub allow_squash_merge: Option, pub allow_merge_commit: Option, pub allow_update_branch: Option, pub allow_forking: Option, pub subscribers_count: Option, pub network_count: Option, pub license: Option, pub allow_auto_merge: Option, pub delete_branch_on_merge: Option, pub parent: Option>, pub source: Option>, } #[derive(Debug, Clone, PartialEq, Deserialize)] #[non_exhaustive] pub struct Subject { pub title: String, pub url: Option, pub latest_comment_url: Option, pub r#type: String, } /// Get new notifications. /// Returns: notifications and new last-modified value. pub fn get_new_notifications( pat: &str, last_modified: Option<&str>, ) -> Result<(Vec, Option), Box> { let mut resp = ureq::get("https://api.github.com/notifications").header("Authorization", &format!("Bearer {pat}")); if let Some(val) = last_modified { resp = resp.header("If-Modified-Since", val); } let json = resp.call()?.into_body().read_to_string()?; let items: Vec = serde_json::from_str(&json)?; let new_last_modified = items.get(0).map(|x| x.updated_at.clone()); let last_modified = if let Some(lm) = new_last_modified { // parse and increase by five seconds let format = format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]Z"); let mut dt = PrimitiveDateTime::parse(&lm, format)?; dt += time::Duration::seconds(5); Some(dt.format(&format)?) } else { last_modified.map(|x| x.to_owned()) }; Ok((items, last_modified)) }