issuerss/src/github/mod.rs

293 lines
11 KiB
Rust

mod structs;
use pulldown_cmark::{Options, Parser};
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::Writer;
use reqwest::{
header::{HeaderMap, HeaderValue},
ClientBuilder,
};
use std::env;
use std::io::Cursor;
use std::iter::Skip;
extern crate serde_json;
pub async fn run(mut args: Skip<env::Args>) {
let repo = args.next().expect("Missing repo");
let issue_number = args.next().expect("Missing issue number");
let mut header_map = HeaderMap::new();
header_map.insert(
"accept",
HeaderValue::from_static("application/vnd.github.v3+json"),
);
let client = ClientBuilder::new()
.default_headers(header_map)
.user_agent(&format!(
"{}/{}",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION")
))
.build()
.unwrap();
let text = client
.get(&format!(
"https://api.github.com/repos/{}/issues/{}",
repo, issue_number
))
.send()
.await
.unwrap()
.text()
.await
.unwrap();
let issue: structs::Issue = serde_json::from_str(&text).unwrap();
let text = client
.get(&issue.events_url)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
let mut events: Vec<structs::EventType> = serde_json::from_str(&text).unwrap();
let text = client
.get(&issue.comments_url)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
let comments: Vec<structs::EventType> = serde_json::from_str(&text).unwrap();
events.extend(comments);
events.sort_by(|i, j| {
let i = match i {
structs::EventType::Comment(comment) => comment.created_at,
structs::EventType::Event(event) => event.created_at,
};
let j = match j {
structs::EventType::Comment(comment) => comment.created_at,
structs::EventType::Event(event) => event.created_at,
};
i.partial_cmp(&j).unwrap()
});
let mut writer = Writer::new(Cursor::new(Vec::new()));
{
let mut elem = BytesStart::owned(b"rss".to_vec(), 3);
elem.push_attribute(("version", "2.0"));
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesStart::owned(b"channel".to_vec(), 7);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesStart::owned(b"title".to_vec(), 5);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&issue.title).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"title".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let elem = BytesStart::owned(b"link".to_vec(), 4);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&issue.html_url).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"link".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let elem = BytesStart::owned(b"description".to_vec(), 11);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&format!("Comments and events from {}", &issue.title))
.into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"description".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let elem = BytesStart::owned(b"item".to_vec(), 4);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesStart::owned(b"title".to_vec(), 5);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&issue.title).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"title".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let elem = BytesStart::owned(b"link".to_vec(), 4);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&issue.html_url).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"link".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let mut elem = BytesStart::owned(b"guid".to_vec(), 4);
elem.push_attribute(("isPermaLink", "false"));
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&issue.node_id).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"guid".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let elem = BytesStart::owned(b"author".to_vec(), 6);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&issue.user.login).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"author".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let elem = BytesStart::owned(b"pubDate".to_vec(), 7);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&issue.created_at.to_rfc2822()).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"pubDate".to_vec());
writer.write_event(Event::End(elem)).unwrap();
if !issue.body.is_empty() {
let elem = BytesStart::owned(b"description".to_vec(), 11);
writer.write_event(Event::Start(elem)).unwrap();
let parser = Parser::new_ext(&issue.body, Options::all());
let mut html_buf = String::with_capacity(issue.body.len());
pulldown_cmark::html::push_html(&mut html_buf, parser);
let elem = BytesText::from_plain_str(html_buf.trim()).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"description".to_vec());
writer.write_event(Event::End(elem)).unwrap();
}
let elem = BytesEnd::owned(b"item".to_vec());
writer.write_event(Event::End(elem)).unwrap();
}
for event in events {
let (title, link, description, author, guid, pub_date) = match event {
structs::EventType::Comment(comment) => {
let parser = Parser::new_ext(&comment.body, Options::all());
let mut html_buf = String::with_capacity(comment.body.len());
pulldown_cmark::html::push_html(&mut html_buf, parser);
let mut title = comment.body.splitn(2, '\n').next().unwrap().to_string();
if title.len() > 80 {
title = format!("{}...", title.split_at(80).0);
}
(
title,
Some(comment.html_url),
html_buf.trim().to_string(),
comment.user.login,
comment.node_id,
comment.created_at.to_rfc2822(),
)
}
structs::EventType::Event(event) => {
let mut text = "Extra fields:\n<pre><code>".to_string();
pulldown_cmark::escape::escape_html(
&mut text,
&serde_json::to_string_pretty(&event.extra)
.unwrap_or_else(|_| format!("{:?}", &event.extra)),
)
.unwrap();
text.push_str("</code></pre>");
(
format!("New event: {}", &event.event),
None,
text,
event.actor.login,
event.node_id,
event.created_at.to_rfc2822(),
)
}
};
let elem = BytesStart::owned(b"item".to_vec(), 4);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesStart::owned(b"title".to_vec(), 5);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&title).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"title".to_vec());
writer.write_event(Event::End(elem)).unwrap();
if let Some(link) = link {
let elem = BytesStart::owned(b"link".to_vec(), 4);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&link).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"link".to_vec());
writer.write_event(Event::End(elem)).unwrap();
}
let mut elem = BytesStart::owned(b"guid".to_vec(), 4);
elem.push_attribute(("isPermaLink", "false"));
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&guid).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"guid".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let elem = BytesStart::owned(b"author".to_vec(), 6);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&author).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"author".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let elem = BytesStart::owned(b"pubDate".to_vec(), 7);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&pub_date).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"pubDate".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let elem = BytesStart::owned(b"description".to_vec(), 11);
writer.write_event(Event::Start(elem)).unwrap();
let elem = BytesText::from_plain_str(&description).into_owned();
writer.write_event(Event::Text(elem)).unwrap();
let elem = BytesEnd::owned(b"description".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let elem = BytesEnd::owned(b"item".to_vec());
writer.write_event(Event::End(elem)).unwrap();
}
let elem = BytesEnd::owned(b"channel".to_vec());
writer.write_event(Event::End(elem)).unwrap();
let elem = BytesEnd::owned(b"rss".to_vec());
writer.write_event(Event::End(elem)).unwrap();
println!(
"{}",
String::from_utf8(writer.into_inner().into_inner()).unwrap()
);
}