OAS: yaml to json
This commit is contained in:
parent
55dd3fffe5
commit
e83ed3d8ea
9 changed files with 92 additions and 424 deletions
20
Cargo.lock
generated
20
Cargo.lock
generated
|
@ -949,6 +949,12 @@ version = "0.15.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
|
@ -1229,9 +1235,11 @@ dependencies = [
|
|||
"sailfish",
|
||||
"serde 1.0.125",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sqlx",
|
||||
"url",
|
||||
"validator",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2432,6 +2440,18 @@ dependencies = [
|
|||
"serde 1.0.125",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
|
||||
dependencies = [
|
||||
"dtoa",
|
||||
"linked-hash-map",
|
||||
"serde 1.0.125",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.9.4"
|
||||
|
|
|
@ -44,6 +44,7 @@ derive_more = "0.99"
|
|||
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
serde_yaml = "0.8"
|
||||
|
||||
url = "2.2"
|
||||
|
||||
|
@ -58,3 +59,8 @@ m_captcha = { version = "0.1.2", git = "https://github.com/mCaptcha/mCaptcha" }
|
|||
rand = "0.8"
|
||||
|
||||
sailfish = "0.3.2"
|
||||
|
||||
[build-dependencies]
|
||||
serde_yaml = "0.8"
|
||||
serde_json = "1"
|
||||
yaml-rust = "0.4"
|
||||
|
|
8
build.rs
8
build.rs
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
// note: add error checking yourself.
|
||||
let output = Command::new("git")
|
||||
|
@ -24,4 +25,11 @@ fn main() {
|
|||
.unwrap();
|
||||
let git_hash = String::from_utf8(output.stdout).unwrap();
|
||||
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
|
||||
|
||||
let yml = include_str!("./openapi.yaml");
|
||||
let api_json: serde_json::Value = serde_yaml::from_str(yml).unwrap();
|
||||
println!(
|
||||
"cargo:rustc-env=OPEN_API_DOCS={}",
|
||||
serde_json::to_string(&api_json).unwrap()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
window.onload = function() {
|
||||
// Begin Swagger UI call region
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "/docs/swagger.json",
|
||||
url: "/docs/openapi.json",
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
|
|
|
@ -1,382 +0,0 @@
|
|||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"version": "0.1.0",
|
||||
"title": "mCaptcha/guard"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "/"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/api//signup": {
|
||||
"post": {
|
||||
"summary": "Registration endpoint",
|
||||
"operationId": "registerUser",
|
||||
"tags": ["user"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/RegisterUser"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful registration"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request: username contains profainity/blacklisted words or email not acceptable or password too long/short or duplicate username/password",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api//signin": {
|
||||
"post": {
|
||||
"summary": "Login endpoint",
|
||||
"operationId": "loginUser",
|
||||
"tags": ["user", "authentication"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/LoginUser"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful authentication"
|
||||
},
|
||||
"401": {
|
||||
"description": "authentication failed, wrong password",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "username not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api//signout": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"cookieAuth": []
|
||||
}
|
||||
],
|
||||
"summary": "Signout endpoint",
|
||||
"operationId": "signoutUser",
|
||||
"tags": ["user", "authentication"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api//account/delete": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"cookieAuth": []
|
||||
}
|
||||
],
|
||||
"summary": "Delete user account",
|
||||
"operationId": "deleteUserAccount",
|
||||
"tags": ["user"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/DeleteUser"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"401": {
|
||||
"description": "(cookie)authentication required or wrong password",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "username not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api//account/username/exists": {
|
||||
"post": {
|
||||
"summary": "Check if username exists",
|
||||
"operationId": "usernameExists",
|
||||
"tags": ["user"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UserDetailCheck"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UserDetailCheckRes"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api//account/email/exists": {
|
||||
"post": {
|
||||
"summary": "Check if email exists",
|
||||
"operationId": "emailExists",
|
||||
"tags": ["user"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UserDetailCheck"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UserDetailCheckRes"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api//meta/build": {
|
||||
"post": {
|
||||
"summary": "Check if email exists",
|
||||
"operationId": "emailExists",
|
||||
"tags": ["user"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/BuildDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"RegisterUser": {
|
||||
"type": "object",
|
||||
"required": ["username", "password", "email"],
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"format": "password"
|
||||
}
|
||||
}
|
||||
},
|
||||
"LoginUser": {
|
||||
"type": "object",
|
||||
"required": ["username", "password"],
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"format": "password"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DeleteUser": {
|
||||
"type": "object",
|
||||
"required": ["password"],
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string",
|
||||
"format": "password"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Error": {
|
||||
"type": "object",
|
||||
"required": ["error"],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"User": {
|
||||
"type": "object",
|
||||
"required": ["id", "name"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"UserDetailCheck": {
|
||||
"type": "object",
|
||||
"required": ["val"],
|
||||
"properties": {
|
||||
"val": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"UserDetailCheckRes": {
|
||||
"type": "object",
|
||||
"required": ["exists"],
|
||||
"properties": {
|
||||
"val": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"BuildDetails": {
|
||||
"type": "object",
|
||||
"required": ["version", "git_commit_hash"],
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "string"
|
||||
},
|
||||
"git_commit_hash": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"securitySchemes": {
|
||||
"cookieAuth": {
|
||||
"type": "apiKey",
|
||||
"in": "cookie",
|
||||
"name": "Authorization"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
15
src/docs.rs
15
src/docs.rs
|
@ -46,12 +46,20 @@ async fn dist(path: web::Path<String>) -> impl Responder {
|
|||
handle_embedded_file(&path.0)
|
||||
}
|
||||
|
||||
#[get("/docs/openapi.json")]
|
||||
async fn spec() -> HttpResponse {
|
||||
HttpResponse::Ok()
|
||||
.content_type("appilcation/json")
|
||||
.body(&*crate::OPEN_API_DOC)
|
||||
}
|
||||
|
||||
#[get("/docs")]
|
||||
async fn index() -> HttpResponse {
|
||||
handle_embedded_file("index.html")
|
||||
}
|
||||
|
||||
pub fn services(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(spec);
|
||||
cfg.service(index);
|
||||
cfg.service(dist);
|
||||
}
|
||||
|
@ -67,7 +75,8 @@ mod tests {
|
|||
#[actix_rt::test]
|
||||
async fn docs_work() {
|
||||
const INDEX: &str = "/docs";
|
||||
const FILE: &str = "/docs/swagger.json";
|
||||
const FILE: &str = "/docs/favicon-32x32.png";
|
||||
const SPEC: &str = "/docs/openapi.json";
|
||||
|
||||
let mut app = test::init_service(App::new().configure(services)).await;
|
||||
|
||||
|
@ -78,5 +87,9 @@ mod tests {
|
|||
let resp =
|
||||
test::call_service(&mut app, test::TestRequest::get().uri(FILE).to_request()).await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
|
||||
let resp =
|
||||
test::call_service(&mut app, test::TestRequest::get().uri(SPEC).to_request()).await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ pub use settings::Settings;
|
|||
lazy_static! {
|
||||
pub static ref SETTINGS: Settings = Settings::new().unwrap();
|
||||
pub static ref GIT_COMMIT_HASH: String = env::var("GIT_HASH").unwrap();
|
||||
pub static ref OPEN_API_DOC: String = env::var("OPEN_API_DOCS").unwrap();
|
||||
pub static ref S: String = env::var("S").unwrap();
|
||||
}
|
||||
|
||||
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
>Username
|
||||
<input
|
||||
class="form__in-field"
|
||||
id="username"
|
||||
type="text"
|
||||
name="username"
|
||||
id="username"
|
||||
|
@ -27,6 +28,7 @@
|
|||
<input
|
||||
class="form__in-field"
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
id="password"
|
||||
required
|
||||
|
@ -45,6 +47,45 @@
|
|||
<p class="form__secondary-action__banner">New to mCaptcha? <a href="/signup" class="form__secondary-action__link">Create account</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
export const SUBMIT = '/';
|
||||
|
||||
export const isBlankString = (event, value, field) => {
|
||||
if (!value.replace(/\s/g, '').length) {
|
||||
event.preventDefautl()
|
||||
alert(`${field} can't be empty`);
|
||||
}
|
||||
};
|
||||
|
||||
const genJsonPayload = payload => {
|
||||
let value = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
};
|
||||
return value;
|
||||
};
|
||||
|
||||
const submit = async e => {
|
||||
let name = document.getElementById('username').value;
|
||||
isBlankString(e, name, 'username');
|
||||
|
||||
let password = document.getElementById('password').value;
|
||||
isBlankString(e, email, 'email');
|
||||
|
||||
let payload = {
|
||||
username,
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
let form = document.getElementById('form');
|
||||
|
||||
form.addEventListener('submit', submit, true);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
<style>
|
||||
* {
|
||||
|
@ -141,43 +182,4 @@
|
|||
}
|
||||
|
||||
</style>
|
||||
<script>
|
||||
export const SUBMIT = '/';
|
||||
|
||||
export const isBlankString = (event, value, field) => {
|
||||
if (!value.replace(/\s/g, '').length) {
|
||||
event.preventDefautl()
|
||||
alert(`${field} can't be empty`);
|
||||
}
|
||||
};
|
||||
|
||||
export const genJsonPayload = payload => {
|
||||
let value = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
};
|
||||
return value;
|
||||
};
|
||||
|
||||
const submit = async e => {
|
||||
let name = document.getElementById('name').value;
|
||||
isBlankString(e, name, 'Name');
|
||||
|
||||
let registration_number = document.getElementById('email').value;
|
||||
isBlankString(e, registration_number, 'Registration number');
|
||||
|
||||
let email = document.getElementById('email').value;
|
||||
isBlankString(e, email, 'email');
|
||||
|
||||
console.log(`from signup: PoW: ${pow}`);
|
||||
|
||||
};
|
||||
|
||||
let form = document.getElementById('form');
|
||||
|
||||
form.addEventListener('submit', submit, true);
|
||||
</script>
|
||||
</html>
|
||||
|
|
Loading…
Reference in a new issue