diff --git a/.gitmodules b/.gitmodules index c27ea82..dbb6627 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,2 +1,3 @@ [submodule "swagger"] + path = swagger url = https://git.exmods.org/NGnius/rusty-gitea diff --git a/Cargo.toml b/Cargo.toml index f10a44e..eb65489 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo" -version = "0.3.0" +version = "0.4.0" authors = ["NGnius "] edition = "2018" @@ -12,3 +12,7 @@ clap = "2.33.0" serde_json = "1.0" regex = "1.3.6" swagger = { path = "swagger" } +hyper = "0.11.6" +hyper-tls = "0.1.4" +tokio-core = "0.1.9" +futures = "0.1.16" diff --git a/src/commands.rs b/src/commands.rs index cad7073..7eda11d 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,7 +1,9 @@ mod cmd_macro; mod cmd_preview; +mod cmd_gitea; pub use self::{ cmd_macro::CmdMacro, cmd_preview::CmdPreview, + cmd_gitea::CmdGitea, }; diff --git a/src/commands/cmd_gitea.rs b/src/commands/cmd_gitea.rs new file mode 100644 index 0000000..3e70a6a --- /dev/null +++ b/src/commands/cmd_gitea.rs @@ -0,0 +1,174 @@ +use std::env; +use std::str::FromStr; + +extern crate serenity; +use serenity::{ + model::channel::Message, + //model::channel::Attachment, + prelude::*, + utils::MessageBuilder, + utils::Colour, +}; + +extern crate regex; +use regex::{Regex, RegexBuilder}; + +extern crate swagger; +use swagger::apis; +//use swagger::apis::RepositoryApi; + +extern crate hyper; +use hyper::{Client, Uri}; + +extern crate hyper_tls; +use hyper_tls::HttpsConnector; + +extern crate tokio_core; +use tokio_core::reactor::Core; + +extern crate futures; +use futures::prelude::Future; + +use crate::traits::Command; + +pub struct CmdGitea { + format: Regex, + help_format: Regex, +} + +impl Command for CmdGitea { + fn execute(&mut self, ctx: &Context, msg: &Message) { + if let Some(parsed) = self.format.captures(&msg.content) { + if let Some(op) = parsed.get(1) { + if op.as_str() != "release" { + let response = MessageBuilder::new() + .push("Invalid operation specified. Supported operations are `release`") + .build(); + if let Err(why) = msg.channel_id.say(&ctx.http, response) { + println!("Failed to send gitea invalid option message {:?}", why); + } + } + if let Some(full_url) = parsed.get(2) { + let token = env::var("GITEA_TOKEN").expect("Expected a Gitea API token in GITEA_TOKEN environment variable"); + let core = Core::new().unwrap(); + let https = HttpsConnector::new(); + let client = Client::configure() + .connector(HttpsConnector::new(4, &core.handle()).unwrap()) + .build(&core.handle()); + let mut config = apis::configuration::Configuration::new(client); + config.api_key = Some(apis::configuration::ApiKey { + prefix: Some("token ".to_string()), + key: token, + }); + println!("Url {}", full_url.as_str()); + match Uri::from_str(full_url.as_str()) { + Err(why) => { + let response = MessageBuilder::new() + .push(format!("Could not parse repository URL {:?}", why)) + .build(); + if let Err(why) = msg.channel_id.say(&ctx.http, response) { + println!("Failed to send gitea error message {:?}", why); + return; + } + } + Ok(url) => { + config.base_path = url.scheme().unwrap().to_owned() + "://" + url.host().unwrap() + "/api/v1/"; + println!("Base Url {}", config.base_path); + let client = apis::client::APIClient::new(config); + if let Some(owner) = parsed.get(3) { + if let Some(repo_name) = parsed.get(4) { + println!("owner {} repo {}", owner.as_str(), repo_name.as_str()); + let future = client.repository_api().repo_list_releases(owner.as_str(), repo_name.as_str(), 1, 5); + match future.wait() { + Ok(items) => { + // items is Vec of release + if items.len() > 0 { + println!("Release info {:?}", items[0]); + // releases found, use first one (most recent) + if let Err(why) = msg.channel_id.send_message(&ctx.http, |m| { + return m.embed(|e| { + return e.colour(Colour::from_rgb(0, 200, 0)) + .title(items[0].tag_name().unwrap()) + .description(items[0].body().unwrap()) + .author(|a| { + return a.name(items[0].name().unwrap()) + .url(full_url.as_str().to_owned() + "/releases"); + }) + }); + }) { + println!("Failed to send gitea release message {:?}", why); + return; + } + } else { + let response = MessageBuilder::new() + .push(format!("No releases found for <{}>", full_url.as_str())) + .build(); + if let Err(why) = msg.channel_id.say(&ctx.http, response) { + println!("Failed to send gitea error message {:?}", why); + return; + } + } + } + Err(reason) => { + println!("Gitea API request failed {:?}", reason); + let response = MessageBuilder::new() + .push(format!("Gitea API request failed {:?}", reason)) + .build(); + if let Err(why) = msg.channel_id.say(&ctx.http, response) { + println!("Failed to send gitea error message {:?}", why); + return; + } + } + } + } + } + } + } + + } + + } + } + let response = MessageBuilder::new() + .push(format!("Unknown error occurred")) + .build(); + if let Err(why) = msg.channel_id.say(&ctx.http, response) { + println!("Failed to send gitea unknown error message {:?}", why); + return; + } + } + + fn valid(&self, _ctx: &Context, msg: &Message) -> bool { + return self.format.is_match(&msg.content) && !msg.author.bot; + } + + fn help(&self, ctx: &Context, msg:&Message) { + let mut response = MessageBuilder::new(); + response.push("**Access the gitea API**\n!gitea release (repository URL)"); + if let Err(why) = msg.channel_id.say(&ctx.http, &response.build()) { + println!("Failed to send gitea help message {:?}", why); + } + } + + fn valid_help(&self, _ctx: &Context, msg: &Message) -> bool { + return self.help_format.is_match(&msg.content); + } +} + +impl CmdGitea { + pub fn new() -> CmdGitea { + return CmdGitea { + format: + RegexBuilder::new(r#"^!gitea\s+(release)\s+?"#) + .multi_line(true) + .case_insensitive(true) + .build() + .unwrap(), + help_format: + RegexBuilder::new(r#"^!help\s*(?:gitea)"#) + .case_insensitive(true) + .build() + .unwrap(), + }; + } +} diff --git a/src/main.rs b/src/main.rs index f131a49..118c3e5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -68,6 +68,7 @@ fn main() { let mut commands = std::vec::Vec::>::new(); commands.push(Box::new(commands::CmdMacro::new())); commands.push(Box::new(commands::CmdPreview::new())); + commands.push(Box::new(commands::CmdGitea::new())); // start bot let mut client = Client::new(&token, event_handler).expect("Error creating client"); {