aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFuwn <[email protected]>2021-04-26 15:42:39 -0700
committerFuwn <[email protected]>2021-04-26 15:42:39 -0700
commit1b82b0a7776aee31f553fb588be4fa9691592248 (patch)
treed0a678e4a6735dfd92e92b1aab33a3447c3666ee /src
parentfmt: Change case (diff)
downloadapi-1b82b0a7776aee31f553fb588be4fa9691592248.tar.xz
api-1b82b0a7776aee31f553fb588be4fa9691592248.zip
major: :star:
Diffstat (limited to 'src')
-rw-r--r--src/constants.rs8
-rw-r--r--src/main.rs27
-rw-r--r--src/routes.rs78
-rw-r--r--src/structures.rs28
-rw-r--r--src/utils.rs52
5 files changed, 193 insertions, 0 deletions
diff --git a/src/constants.rs b/src/constants.rs
new file mode 100644
index 0000000..adbde90
--- /dev/null
+++ b/src/constants.rs
@@ -0,0 +1,8 @@
+// Copyleft 2021-2021 The Senpy Club
+// SPDX-License-Identifier: GPL-3.0-only
+
+pub const GITHUB_USER_CONTENT: &str =
+ "https://raw.githubusercontent.com/laynH/Anime-Girls-Holding-Programming-Books/master/";
+pub const GITHUB_API_ENDPOINT: &str = "https://api.github.com/repos/laynH/Anime-Girls-Holding-Progr\
+amming-Books/git/trees/master?recursive=1";
+pub const USER_AGENT: &str = env!("CARGO_PKG_NAME");
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..35af208
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,27 @@
+// Copyleft 2021-2021 The Senpy Club
+// SPDX-License-Identifier: GPL-3.0-only
+
+#![feature(proc_macro_hygiene, decl_macro, type_ascription)]
+
+#[macro_use]
+extern crate rocket;
+
+pub mod constants;
+pub mod routes;
+pub mod structures;
+pub mod utils;
+
+#[launch]
+fn rocket() -> _ {
+ dotenv::dotenv().ok();
+
+ rocket::build().mount("/", routes![routes::index]).mount(
+ "/api/v1",
+ routes![
+ routes::github,
+ routes::languages,
+ routes::language,
+ routes::random
+ ],
+ )
+}
diff --git a/src/routes.rs b/src/routes.rs
new file mode 100644
index 0000000..e492404
--- /dev/null
+++ b/src/routes.rs
@@ -0,0 +1,78 @@
+// Copyleft 2021-2021 The Senpy Club
+// SPDX-License-Identifier: GPL-3.0-only
+
+use rand::{thread_rng, Rng};
+use rocket_contrib::json::Json;
+
+use crate::{
+ structures::{GitHubAPIResponse, SenpyRandom},
+ utils::{filter_images_by_language, filter_languages, github_api},
+};
+
+#[get("/")]
+pub fn index() -> &'static str {
+ r#"# senpy-api
+## routes
+if a language requires a parameter, it will be notated like <this>.
+for example; if a route is notated as "/api/v1/route?<parameter>", you can
+access that route via the url
+"http://this.domain/api/v1/route?parameter=something"
+
+- /
+ - /: index page (you are here)
+
+- /api/v1
+ - /github: github api mirror
+ - /languages: a list of all languages that appear in _the_ repository
+ - /language?<lang>: get a list of all images that pertain to the language "<lang>"
+
+## notes
+### rate-limit (s)
+there aren't any rate-limits or whatnot on api usage but don't abuse it, it only takes one bad
+apple to spoil the lot.
+
+### contributing
+if you'd like to support the project in anyway, check out the repository!
+https://github.com/senpy-club/api
+
+### supporting
+if you would like to support my development ventures, visit my github profile here :3
+https://github.com/fuwn
+
+### license
+gnu general public license v3.0 (gpl-3.0-only)
+https://github.com/senpy-club/api/blob/main/LICENSE"#
+}
+
+#[get("/github")]
+pub async fn github() -> Json<GitHubAPIResponse> { Json(github_api().await.unwrap()) }
+
+#[get("/languages")]
+pub async fn languages() -> Json<Vec<String>> { Json(filter_languages().await) }
+
+#[get("/language?<lang>")]
+pub async fn language(lang: Option<String>) -> Json<Vec<String>> {
+ // lang.map(async |lang| Json(filter_images_by_language(lang).await))
+ // .unwrap_or_else(|| Json(vec!["invalid language or no language
+ // specified".to_string()]));
+
+ return if lang.is_none() {
+ Json(vec!["invalid language or no language specified".to_string()])
+ } else {
+ Json(filter_images_by_language(lang.unwrap()).await)
+ };
+}
+
+#[get("/random")]
+pub async fn random() -> Json<SenpyRandom> {
+ let filtered_languages = filter_languages().await;
+ let random_language =
+ &filtered_languages[thread_rng().gen_range(0..filtered_languages.len() - 1)];
+ let filtered_images = filter_images_by_language(random_language.clone().to_owned()).await;
+ let random_image = &filtered_images[thread_rng().gen_range(0..filtered_images.len() - 1)];
+
+ Json(SenpyRandom {
+ language: random_language.clone().to_owned(),
+ image: random_image.clone().to_owned(),
+ })
+}
diff --git a/src/structures.rs b/src/structures.rs
new file mode 100644
index 0000000..2a85111
--- /dev/null
+++ b/src/structures.rs
@@ -0,0 +1,28 @@
+// Copyleft 2021-2021 The Senpy Club
+// SPDX-License-Identifier: GPL-3.0-only
+
+use serde_derive::{Deserialize, Serialize};
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct GitHubAPIResponse {
+ pub sha: String,
+ pub url: String,
+ pub tree: Vec<GitHubAPIResponseTree>,
+ pub truncated: bool,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct GitHubAPIResponseTree {
+ pub path: String,
+ pub mode: String,
+ #[serde(rename = "type")]
+ pub _type: String,
+ pub sha: String,
+ pub url: String,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct SenpyRandom {
+ pub(crate) language: String,
+ pub image: String,
+}
diff --git a/src/utils.rs b/src/utils.rs
new file mode 100644
index 0000000..d51a813
--- /dev/null
+++ b/src/utils.rs
@@ -0,0 +1,52 @@
+// Copyleft 2021-2021 The Senpy Club
+// SPDX-License-Identifier: GPL-3.0-only
+
+use crate::{
+ constants::{GITHUB_API_ENDPOINT, GITHUB_USER_CONTENT, USER_AGENT},
+ structures::GitHubAPIResponse,
+};
+
+pub async fn github_api() -> Result<GitHubAPIResponse, reqwest::Error> {
+ Ok(
+ reqwest::Client::new()
+ .get(GITHUB_API_ENDPOINT)
+ .header("User-Agent", USER_AGENT)
+ .header(
+ "Authorization",
+ format!("token {}", std::env::var("GITHUB_TOKEN").unwrap()),
+ )
+ .send()
+ .await?
+ .json::<GitHubAPIResponse>()
+ .await?,
+ )
+}
+
+pub async fn filter_languages() -> Vec<String> {
+ let mut languages = vec![];
+
+ for i in github_api().await.unwrap().tree {
+ if i._type == "tree" {
+ languages.push(i.path);
+ }
+ }
+
+ languages
+}
+
+pub async fn filter_images_by_language(language: String) -> Vec<String> {
+ let mut images = vec![];
+
+ for i in github_api().await.unwrap().tree {
+ // Example:
+ // "Language/Image.png" would become ["Language", "Image.png"]
+
+ // TODO: Fix this with type_ascription
+ let x: Vec<&str> = i.path.split("/").collect();
+ if x[0] == language && i.path.contains('/') {
+ images.push(format!("{}{}", GITHUB_USER_CONTENT, i.path))
+ }
+ }
+
+ images
+}