diff --git a/Cargo.toml b/Cargo.toml index fe7fb4ff..7f81b0ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,8 @@ all. authors = ["Aliaksei BialĂ­auski ", "Ivanchuk Ivan "] [dependencies] -clippy = "0.0.302" -serde = "1.0.203" +serde = { version = "1.0.203", features = ["derive"] } +serde_json = "1.0.117" anyhow = "1.0.86" +axum = "0.7.5" +tokio = { version = "1.0.0", features = ["rt", "rt-multi-thread", "macros", "fs"] } diff --git a/clippy.toml b/clippy.toml index a80f5949..1351e239 100644 --- a/clippy.toml +++ b/clippy.toml @@ -19,5 +19,3 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. - -disallowed-names = ["not-jeff"] \ No newline at end of file diff --git a/resources/home.json b/resources/home.json new file mode 100644 index 00000000..b089acdc --- /dev/null +++ b/resources/home.json @@ -0,0 +1,35 @@ +{ + "current_user_url": "http://localhost:{port}/user", + "current_user_authorizations_html_url": "https://github.com/settings/connections/applications{/client_id}", + "authorizations_url": "http://localhost:{port}/authorizations", + "code_search_url": "http://localhost:{port}/search/code?q={query}{&page,per_page,sort,order}", + "commit_search_url": "http://localhost:{port}/search/commits?q={query}{&page,per_page,sort,order}", + "emails_url": "http://localhost:{port}/user/emails", + "emojis_url": "http://localhost:{port}/emojis", + "events_url": "http://localhost:{port}/events", + "feeds_url": "http://localhost:{port}/feeds", + "followers_url": "http://localhost:{port}/user/followers", + "following_url": "http://localhost:{port}/user/following{/target}", + "gists_url": "http://localhost:{port}/gists{/gist_id}", + "hub_url": "http://localhost:{port}/hub", + "issue_search_url": "http://localhost:{port}/search/issues?q={query}{&page,per_page,sort,order}", + "issues_url": "http://localhost:{port}/issues", + "keys_url": "http://localhost:{port}/user/keys", + "label_search_url": "http://localhost:{port}/search/labels?q={query}&repository_id={repository_id}{&page,per_page}", + "notifications_url": "http://localhost:{port}/notifications", + "organization_url": "http://localhost:{port}/orgs/{org}", + "organization_repositories_url": "http://localhost:{port}/orgs/{org}/repos{?type,page,per_page,sort}", + "organization_teams_url": "http://localhost:{port}/orgs/{org}/teams", + "public_gists_url": "http://localhost:{port}/gists/public", + "rate_limit_url": "http://localhost:{port}/rate_limit", + "repository_url": "http://localhost:{port}/repos/{owner}/{repo}", + "repository_search_url": "http://localhost:{port}/search/repositories?q={query}{&page,per_page,sort,order}", + "current_user_repositories_url": "http://localhost:{port}/user/repos{?type,page,per_page,sort}", + "starred_url": "http://localhost:{port}/user/starred{/owner}{/repo}", + "starred_gists_url": "http://localhost:{port}/gists/starred", + "topic_search_url": "http://localhost:{port}/search/topics?q={query}{&page,per_page}", + "user_url": "http://localhost:{port}/users/{user}", + "user_organizations_url": "http://localhost:{port}/user/orgs", + "user_repositories_url": "http://localhost:{port}/users/{user}/repos{?type,page,per_page,sort}", + "user_search_url": "http://localhost:{port}/search/users?q={query}{&page,per_page,sort,order}" +} diff --git a/src/main.rs b/src/main.rs index 8b7800a8..e7dee931 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,14 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +use axum::routing::get; +use axum::Router; +mod routes; +use crate::routes::home; -fn main() { - println!("Hello, world!"); +#[tokio::main] +async fn main() { + let app = Router::new().route("/", get(home::home)); + let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); + axum::serve(listener, app).await.unwrap(); } diff --git a/src/routes/home.rs b/src/routes/home.rs new file mode 100644 index 00000000..d5a5c0ba --- /dev/null +++ b/src/routes/home.rs @@ -0,0 +1,59 @@ +// The MIT License (MIT) +// +// Copyright (c) 2024 Aliaksei Bialiauski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +use std::collections::HashMap; +use std::error::Error; + +use crate::routes::rs_err::RsErr; +use axum::http::StatusCode; +use axum::response::IntoResponse; +use axum::Json; +use tokio::fs; + +// @todo #9:25min Create unit tests for home.rs. +// We need to create a few unit testes for home endpoints, +// bootstrapping, and fetching. Don't forget to remove this puzzle. +pub async fn home() -> impl IntoResponse { + match json("resources/home.json").await { + Ok(content) => { + let objs = serde_json::from_str(&content).unwrap(); + Json(objs) + } + Err(e) => Json( + serde_json::to_value(RsErr { + status: StatusCode::INTERNAL_SERVER_ERROR.to_string(), + message: "Failed to fetch home (/) endpoints".to_owned(), + trace: e.to_string(), + }) + .unwrap(), + ), + } +} + +async fn json(path: &str) -> Result> { + let content = fs::read_to_string(path).await.unwrap(); + let mut data: HashMap = serde_json::from_str(&content).unwrap(); + for value in data.values_mut() { + *value = value.replace("{port}", "3000"); + } + let updated = serde_json::to_string(&data).unwrap(); + Ok(updated) +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs new file mode 100644 index 00000000..dc2b5115 --- /dev/null +++ b/src/routes/mod.rs @@ -0,0 +1,23 @@ +// The MIT License (MIT) +// +// Copyright (c) 2024 Aliaksei Bialiauski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +pub mod home; +pub mod rs_err; diff --git a/src/routes/rs_err.rs b/src/routes/rs_err.rs new file mode 100644 index 00000000..e0d54b3c --- /dev/null +++ b/src/routes/rs_err.rs @@ -0,0 +1,29 @@ +// The MIT License (MIT) +// +// Copyright (c) 2024 Aliaksei Bialiauski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +use serde::Serialize; + +#[derive(Serialize)] +pub struct RsErr { + pub status: String, + pub message: String, + pub trace: String, +}