1
0
Fork 0
mirror of https://github.com/mCaptcha/mCaptcha.git synced 2025-02-13 23:19:46 +03:00

swagger ui

This commit is contained in:
realaravinth 2021-03-30 20:49:09 +05:30
parent 8cc3146389
commit a3a118927e
No known key found for this signature in database
GPG key ID: AD9F0F08E855ED88
25 changed files with 962 additions and 22 deletions

55
Cargo.lock generated
View file

@ -1222,8 +1222,10 @@ dependencies = [
"lazy_static",
"log",
"m_captcha",
"mime_guess",
"pretty_env_logger",
"rand 0.8.3",
"rust-embed",
"sailfish",
"serde 1.0.125",
"serde_json",
@ -2206,6 +2208,39 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "rust-embed"
version = "5.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fe1fe6aac5d6bb9e1ffd81002340363272a7648234ec7bdfac5ee202cb65523"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
"walkdir",
]
[[package]]
name = "rust-embed-impl"
version = "5.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed91c41c42ef7bf687384439c312e75e0da9c149b0390889b94de3c7d9d9e66"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a512219132473ab0a77b52077059f1c47ce4af7fbdc94503e9862a34422876d"
dependencies = [
"walkdir",
]
[[package]]
name = "rust-ini"
version = "0.13.0"
@ -2277,6 +2312,15 @@ dependencies = [
"sailfish-compiler",
]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
@ -3151,6 +3195,17 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi 0.3.9",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"

View file

@ -28,6 +28,8 @@ actix-identity = "0.3"
actix-http = "2.2"
actix-rt = "1"
actix-files = "0.4"
mime_guess = "2.0.3"
rust-embed = "5.9.0"
futures = "0.3"

BIN
docs/favicon-16x16.png Normal file

Binary file not shown.

After

(image error) Size: 665 B

BIN
docs/favicon-32x32.png Normal file

Binary file not shown.

After

(image error) Size: 628 B

60
docs/index.html Normal file
View file

@ -0,0 +1,60 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "/docs/swagger.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
// End Swagger UI call region
window.ui = ui;
};
</script>
</body>
</html>

75
docs/oauth2-redirect.html Normal file
View file

@ -0,0 +1,75 @@
<!doctype html>
<html lang="en-US">
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};
isValid = qp.state === sentState;
if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
window.addEventListener('DOMContentLoaded', function () {
run();
});
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
docs/swagger-ui.css Normal file

File diff suppressed because one or more lines are too long

1
docs/swagger-ui.css.map Normal file

File diff suppressed because one or more lines are too long

3
docs/swagger-ui.js Normal file

File diff suppressed because one or more lines are too long

1
docs/swagger-ui.js.map Normal file

File diff suppressed because one or more lines are too long

382
docs/swagger.json Normal file
View file

@ -0,0 +1,382 @@
{
"openapi": "3.0.0",
"info": {
"version": "0.1.0",
"title": "mCaptcha/guard"
},
"servers": [
{
"url": "/"
}
],
"paths": {
"/api/v1/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/v1/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/v1/signout": {
"post": {
"security": [
{
"cookieAuth": []
}
],
"summary": "Signout endpoint",
"operationId": "signoutUser",
"tags": [
"user",
"authentication"
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/v1/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/v1/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/v1/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"
}
}
}
}
}
}
}
},
"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"
}
}
}
},
"securitySchemes": {
"cookieAuth": {
"type": "apiKey",
"in": "cookie",
"name": "Authorization"
}
}
}
}

246
openapi.yaml Normal file
View file

@ -0,0 +1,246 @@
openapi: 3.0.0
info:
version: 0.1.0
title: mCaptcha/guard
servers:
- url: 'http://localhost:3000'
paths:
/api/v1/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'
'500':
description: 'Internal server error'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'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'
/api/v1/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'
'500':
description: 'Internal server error'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'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'
/api/v1/signout:
post:
security:
- cookieAuth: []
summary: 'Signout endpoint'
operationId: signoutUser
tags:
- user
- authentication
responses:
'200':
description: 'OK'
/api/v1/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'
'500':
description: 'Internal server error'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'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'
/api/v1/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/v1/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'
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
securitySchemes:
cookieAuth:
type: apiKey
in: cookie
name: Authorization

View file

@ -36,8 +36,9 @@ pub struct Login {
pub password: String,
}
struct Password {
password: String,
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Password {
pub password: String,
}
#[post("/api/v1/signup")]
@ -114,7 +115,7 @@ pub fn is_authenticated(id: &Identity) -> ServiceResult<()> {
#[post("/api/v1/account/delete")]
pub async fn delete_account(
id: Identity,
payload: web::Json<Login>,
payload: web::Json<Password>,
data: web::Data<Data>,
) -> ServiceResult<impl Responder> {
use argon2_creds::Config;
@ -122,10 +123,12 @@ pub async fn delete_account(
is_authenticated(&id)?;
let username = id.identity().unwrap();
let rec = sqlx::query_as!(
Password,
r#"SELECT password FROM mcaptcha_users WHERE name = ($1)"#,
&payload.username,
&username,
)
.fetch_one(&data.db)
.await;
@ -135,12 +138,9 @@ pub async fn delete_account(
match rec {
Ok(s) => {
if Config::verify(&s.password, &payload.password)? {
sqlx::query!(
"DELETE FROM mcaptcha_users WHERE name = ($1)",
&payload.username,
)
.execute(&data.db)
.await?;
sqlx::query!("DELETE FROM mcaptcha_users WHERE name = ($1)", &username)
.execute(&data.db)
.await?;
Ok(HttpResponse::Ok())
} else {
Err(ServiceError::WrongPassword)
@ -153,7 +153,7 @@ pub async fn delete_account(
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AccountCheckPayload {
pub field: String,
pub val: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
@ -168,7 +168,7 @@ pub async fn username_exists(
) -> ServiceResult<impl Responder> {
let res = sqlx::query!(
"SELECT EXISTS (SELECT 1 from mcaptcha_users WHERE name = $1)",
&payload.field,
&payload.val,
)
.fetch_one(&data.db)
.await?;
@ -191,7 +191,7 @@ pub async fn email_exists(
) -> ServiceResult<impl Responder> {
let res = sqlx::query!(
"SELECT EXISTS (SELECT 1 from mcaptcha_users WHERE email = $1)",
&payload.field,
&payload.val,
)
.fetch_one(&data.db)
.await?;

View file

@ -70,7 +70,7 @@ async fn auth_works() {
SIGNIN,
&login,
ServiceError::UsernameNotFound,
StatusCode::UNAUTHORIZED,
StatusCode::NOT_FOUND,
)
.await;
@ -115,9 +115,13 @@ async fn del_userworks() {
let cookies = get_cookie!(signin_resp);
let mut app = get_app!(data).await;
let payload = Password {
password: creds.password,
};
let delete_user_resp = test::call_service(
&mut app,
post_request!(&creds, "/api/v1/account/delete")
post_request!(&payload, "/api/v1/account/delete")
.cookie(cookies)
.to_request(),
)
@ -143,7 +147,7 @@ async fn uname_email_exists_works() {
let cookies = get_cookie!(signin_resp);
let mut app = get_app!(data).await;
let mut payload = AccountCheckPayload { field: NAME.into() };
let mut payload = AccountCheckPayload { val: NAME.into() };
let user_exists_resp = test::call_service(
&mut app,
@ -156,7 +160,7 @@ async fn uname_email_exists_works() {
let mut resp: AccountCheckResp = test::read_body_json(user_exists_resp).await;
assert!(resp.exists);
payload.field = PASSWORD.into();
payload.val = PASSWORD.into();
let user_doesnt_exist = test::call_service(
&mut app,
@ -180,7 +184,7 @@ async fn uname_email_exists_works() {
resp = test::read_body_json(email_doesnt_exist).await;
assert!(!resp.exists);
payload.field = EMAIL.into();
payload.val = EMAIL.into();
let email_exist = test::call_service(
&mut app,

82
src/docs.rs Normal file
View file

@ -0,0 +1,82 @@
/*
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use actix_web::body::Body;
use actix_web::{get, web, HttpResponse, Responder};
use mime_guess::from_path;
use rust_embed::RustEmbed;
use std::borrow::Cow;
#[derive(RustEmbed)]
#[folder = "docs/"]
struct Asset;
pub fn handle_embedded_file(path: &str) -> HttpResponse {
match Asset::get(path) {
Some(content) => {
let body: Body = match content {
Cow::Borrowed(bytes) => bytes.into(),
Cow::Owned(bytes) => bytes.into(),
};
HttpResponse::Ok()
.content_type(from_path(path).first_or_octet_stream().as_ref())
.body(body)
}
None => HttpResponse::NotFound().body("404 Not Found"),
}
}
#[get("/docs/{_:.*}")]
async fn dist(path: web::Path<String>) -> impl Responder {
handle_embedded_file(&path.0)
}
#[get("/docs")]
async fn index() -> HttpResponse {
handle_embedded_file("index.html")
}
pub fn services(cfg: &mut web::ServiceConfig) {
cfg.service(index);
cfg.service(dist);
}
#[cfg(test)]
mod tests {
use actix_web::http::StatusCode;
use actix_web::test;
use super::*;
use crate::*;
#[actix_rt::test]
async fn docs_work() {
const INDEX: &str = "/docs";
const FILE: &str = "/docs/swagger.json";
let mut app = test::init_service(App::new().configure(services)).await;
let resp =
test::call_service(&mut app, test::TestRequest::get().uri(INDEX).to_request()).await;
assert_eq!(resp.status(), StatusCode::OK);
let resp =
test::call_service(&mut app, test::TestRequest::get().uri(FILE).to_request()).await;
assert_eq!(resp.status(), StatusCode::OK);
}
}

View file

@ -118,14 +118,18 @@ impl ResponseError for ServiceError {
ServiceError::NotAnEmail => StatusCode::BAD_REQUEST,
ServiceError::NotAUrl => StatusCode::BAD_REQUEST,
ServiceError::WrongPassword => StatusCode::UNAUTHORIZED,
ServiceError::UsernameNotFound => StatusCode::UNAUTHORIZED,
ServiceError::UsernameNotFound => StatusCode::NOT_FOUND,
ServiceError::AuthorizationRequired => StatusCode::UNAUTHORIZED,
ServiceError::ProfainityError => StatusCode::BAD_REQUEST,
ServiceError::BlacklistError => StatusCode::BAD_REQUEST,
ServiceError::UsernameCaseMappedError => StatusCode::BAD_REQUEST,
ServiceError::PasswordTooShort => StatusCode::BAD_REQUEST,
ServiceError::PasswordTooLong => StatusCode::BAD_REQUEST,
ServiceError::UsernameCaseMappedError => StatusCode::BAD_REQUEST,
ServiceError::UsernameTaken => StatusCode::BAD_REQUEST,
ServiceError::TokenNameTaken => StatusCode::BAD_REQUEST,
ServiceError::TokenNotFound => StatusCode::NOT_FOUND,
ServiceError::HostnameTaken => StatusCode::BAD_REQUEST,

View file

@ -30,6 +30,7 @@ mod data;
mod errors;
//mod routes;
mod api;
mod docs;
mod settings;
//mod templates;
#[cfg(test)]
@ -54,7 +55,9 @@ pub static VERIFICATION_PATH: &str = "mcaptchaVerificationChallenge.json";
#[cfg(not(tarpaulin_include))]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use api::v1::services as v1_services;
use actix_web::web;
use api::v1;
use docs;
pretty_env_logger::init();
info!(
"{}: {}.\nFor more information, see: {}\nBuild info:\nVersion: {} commit: {}",
@ -67,7 +70,9 @@ async fn main() -> std::io::Result<()> {
HttpServer::new(move || {
let client = Client::default();
App::new()
.configure(v1_services)
.configure(v1::services)
.configure(docs::services)
//.service(web::resource("/dist/{_:.*}").route(web::get().to(docs::dist)))
.wrap(middleware::Logger::default())
.wrap(get_identity_service())
.wrap(middleware::Compress::default())