use std::collections::HashMap; use colored::*; use reqwest::StatusCode; use serde_derive::{Deserialize, Serialize}; use crate::request::Request; pub struct Repository; #[derive(Debug, Serialize, Deserialize)] pub struct MultipleRepositories { pub data: Vec, pub ok: bool, } #[derive(Debug, Serialize, Deserialize)] pub struct RepositoryResponse { pub allow_merge_commits: bool, pub allow_rebase: bool, pub allow_rebase_explicit: bool, pub allow_squash_merge: bool, pub archived: bool, pub avatar_url: String, pub clone_url: String, pub created_at: String, pub default_branch: String, pub description: String, pub empty: bool, pub external_tracker: Option, pub external_wiki: Option, pub fork: bool, pub forks_count: u32, pub full_name: String, pub has_issues: bool, pub has_pull_requests: bool, pub has_wiki: bool, pub html_url: String, pub id: u32, pub ignore_whitespace_conflicts: bool, pub internal_tracker: Option, pub mirror: bool, pub name: String, pub open_issues_count: u32, pub open_pr_counter: u32, pub original_url: String, pub owner: Option, pub permissions: Option, pub private: bool, pub release_counter: u32, pub size: u32, pub ssh_url: String, pub stars_count: u32, pub template: bool, pub updated_at: String, pub watchers_count: u32, pub website: String, } #[derive(Debug, Serialize, Deserialize)] pub struct ExternalTracker { pub external_tracker_format: String, pub external_tracker_style: String, pub external_tracker_url: String, } #[derive(Debug, Serialize, Deserialize)] pub struct ExternalWiki { pub external_wiki_url: String, } #[derive(Debug, Serialize, Deserialize)] pub struct InternalTracker { pub allow_only_contributors_to_track_time: bool, pub enable_issue_dependencies: bool, pub enable_time_tracker: bool, } #[derive(Debug, Serialize, Deserialize)] pub struct Owner { pub avatar_url: String, pub created: String, pub email: String, pub full_name: String, pub id: u32, pub is_admin: bool, pub language: String, pub last_login: String, pub login: String, } #[derive(Debug, Serialize, Deserialize)] pub struct Permissions { pub admin: bool, pub pull: bool, pub push: bool, } impl Repository { pub fn new() -> Repository { Repository {} } pub fn create_repo(&self, request: &Request) { let client = &request.client; let arg_value = request .arg_value .subcommand() .1 .unwrap() .value_of("create") .unwrap(); let mut map: HashMap<&str, &str> = HashMap::new(); let url = format!( "{request}/user/repos?token={api_token}", request = request.url.as_ref().unwrap(), api_token = request.authentication.credentials.1.as_ref().unwrap() ); map.insert("name", arg_value); let response = client.post(url.as_str()).json(&map).send(); match response { Ok(repo) => match repo.status() { StatusCode::CREATED => { let deserialized: RepositoryResponse = repo.json().unwrap(); println!("{}", "Repository successfully created!".green()); println!("\tRepository name: {:0}\n\tRepository owner: {:1}\n\tRepository description: {:2}", deserialized.name, deserialized.owner.unwrap().full_name, deserialized.description); } StatusCode::CONFLICT => println!("{}", "Repository already exists!".red()), StatusCode::UNPROCESSABLE_ENTITY => { println!("{}", "Repository input validation failed!".red()) } _ => println!( "Repository creation failed! HTTP status code: {}", repo.status().as_str() ), }, Err(e) => panic!("{}", e), } } pub fn delete_repo(&self, request: &Request) { let client = &request.client; let arg_value: Vec<&str> = request .arg_value .subcommand() .1 .unwrap() .values_of("delete") .unwrap() .collect(); let url = format!( r"{request}/repos/{owner}/{repo}?token={api_token}", request = request.url.as_ref().unwrap(), owner = request.authentication.credentials.0.as_ref().unwrap(), repo = arg_value[1], api_token = request.authentication.credentials.1.as_ref().unwrap(), ); let response = client.delete(&url).send(); match response { Ok(repo) => match repo.status() { StatusCode::NO_CONTENT => println!("{}", "Respository successfully deleted!".green()), StatusCode::FORBIDDEN => println!("{}", "Repository deletion forbidden!".red()), _ => println!( "Repository deletion failed! Does the repository exist? HTTP status code: {}", repo.status().as_str() ), }, Err(e) => panic!("{}", e), } } pub fn fork_repo(&self, request: &Request) { let client = &request.client; let arg_item: Vec<&str> = request .arg_value .subcommand() .1 .unwrap() .values_of("fork") .unwrap() .collect(); let mut map: HashMap<&str, &str> = HashMap::new(); let user = request.authentication.credentials.0.as_ref().unwrap(); let url = format!( "{request}/repos/{owner}/{repo}/forks?token={api_token}", request = request.url.as_ref().unwrap(), owner = arg_item[0], repo = arg_item[1], api_token = request.authentication.credentials.1.as_ref().unwrap(), ); map.insert("name", user.as_str()); let response = client.post(url.as_str()).json(&map).send(); match response { Ok(repo) => match repo.status() { StatusCode::ACCEPTED => { let deserialized: RepositoryResponse = repo.json().unwrap(); println!("{}", "Repository forked successfully".green()); println!("\tOriginal repository name: {:0?}\n\tOriginal repository owner: {:1?}\n\tForked repository name: {:2?}\n\tForked repository owner: {:3?}", deserialized.name, arg_item[0], deserialized.name, deserialized.owner.unwrap().full_name); } StatusCode::INTERNAL_SERVER_ERROR => println!("{}", "Repository already forked!".red()), StatusCode::FORBIDDEN => println!("{}", "Repository fork forbidden!".red()), StatusCode::UNPROCESSABLE_ENTITY => println!("{}", "Repository fork input validation failed!".red()), StatusCode::NOT_FOUND => println!("{}", "Repository not found!"), _ => println!("Repository creation failed! HTTP status code: {}", repo.status().as_str()), }, Err(e) => panic!("{}", e), } } pub fn search_repo(&self, request: &Request) { let client = &request.client; let arg_value = request .arg_value .subcommand() .1 .unwrap() .value_of("search") .unwrap(); let url = format!( "{request}/repos/search?q={query}&token={api_token}", request = request.url.as_ref().unwrap(), query = arg_value, api_token = request.authentication.credentials.1.as_ref().unwrap(), ); let response = client.get(url.as_str()).send(); match response { Ok(repo) => match repo.status() { StatusCode::OK => { let deserialized: MultipleRepositories = repo.json().unwrap(); match deserialized.data.len() != 0 { true => { println!("{}", "List of repositories found:"); for (i, data) in deserialized.data.iter().enumerate() { println!("{}.\tRepository name: {:1}\n\tRepository owner: {:2}\n\tRepository description: {:3}\n", i + 1, data.name, data.owner.as_ref().unwrap().full_name, data.description) } println!("Total number of repositories indexed: {}", deserialized.data.iter().count()) } false => println!("{}", "Repository searched doesn't exist!".red()), } } StatusCode::NOT_FOUND => println!("{}", "Repository searched doesn't exist!".red()), StatusCode::UNPROCESSABLE_ENTITY => println!("{}", "Repository input validation failed!".red()), _ => println!("Repository search failed! HTTP status code: {}", repo.status().as_str()), }, Err(e) => panic!("{}", e), } } pub fn list_repo(&self, request: &Request) { let client = &request.client; let url = format!( "{request}/repos/search?token={api_token}", request = request.url.as_ref().unwrap(), api_token = request.authentication.credentials.1.as_ref().unwrap() ); let response = client.get(url.as_str()).send(); match response { Ok(repo) => match repo.status() { StatusCode::OK => { let deserialized: MultipleRepositories = repo.json().unwrap(); match deserialized.data.len() != 0 { true => { println!("{}", "List of repositories found:"); for (i, data) in deserialized.data.iter().enumerate() { println!("{}.\tRepository name: {:1}\n\tRepository owner: {:2}\n\tRepository description: {:3}\n", i + 1, data.name, data.owner.as_ref().unwrap().full_name, data.description) } println!("Total number of repositories indexed: {}", deserialized.data.iter().count()) }, false => println!("{}", "The authenticated user doesn't have any repositories. Why not create one?".yellow()) } } StatusCode::UNPROCESSABLE_ENTITY => println!("{}", "Repository input validation failed!".red()), _ => println!("Repository search failed! HTTP status code: {}",repo.status().as_str()), }, Err(e) => panic!("{}", e), } } }