516 lines
14 KiB
Rust
516 lines
14 KiB
Rust
use std::env;
|
|
use axum::{
|
|
routing::{get, post},
|
|
http::StatusCode,
|
|
Json, Router,
|
|
};
|
|
use axum::extract::{Path, State};
|
|
use axum::routing::delete;
|
|
use dotenv::dotenv;
|
|
use env_logger::fmt::style::Reset;
|
|
use http::{header, Method};
|
|
use common::models::article::{delete_article, insert_article, load_article, load_articles, update_article, Article};
|
|
use common::models::origin::Origin;
|
|
use sqlx::{ postgres::PgPoolOptions, PgPool };
|
|
use tower_http::cors::{AllowOrigin, Any, CorsLayer};
|
|
use tracing::info;
|
|
use http::header::{AUTHORIZATION, ACCEPT, ACCESS_CONTROL_ALLOW_ORIGIN, CONTENT_TYPE, ACCESS_CONTROL_ALLOW_CREDENTIALS};
|
|
use common::models::article;
|
|
use common::models::label::{delete_label, insert_label, load_labels, update_label, Label};
|
|
use common::models::settings::{load_settings, update_settings, Settings};
|
|
use common::models::supplier::{delete_supplier, insert_supplier, load_suppliers, update_supplier, Supplier};
|
|
use common::models::unit::Unit;
|
|
use common::models::variant::{delete_variant, insert_variant, update_variant, Variant};
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
dotenv().ok();
|
|
|
|
let server_address = env::var("SERVER_ADDRESS").expect("SERVER_ADDRESS is not set in .env file");
|
|
let server_port = env::var("SERVER_PORT").expect("SERVER_PORT is not set in .env file");
|
|
let database = env::var("DATABASE_URL").expect("DATABASE is not set in .env file");
|
|
|
|
let addr = format!("{}:{}", server_address, server_port);
|
|
|
|
// initialize tracing
|
|
tracing_subscriber::fmt().init();
|
|
|
|
let pool = PgPoolOptions::new()
|
|
.max_connections(50)
|
|
.connect(&database)
|
|
.await
|
|
.expect(&format!("Can't connect to database: {}", &database));
|
|
|
|
//sqlx::migrate!().run(&pool).await.expect("Migrations failed");
|
|
|
|
let cors = CorsLayer::new()
|
|
.allow_methods([Method::GET, Method::POST, Method::DELETE])
|
|
.allow_headers([ACCEPT, ACCESS_CONTROL_ALLOW_ORIGIN, CONTENT_TYPE])
|
|
.allow_origin(AllowOrigin::any());
|
|
|
|
// build our application with a route
|
|
let app = Router::new()
|
|
.route("/articles", get(get_articles))
|
|
.route("/article", post(create_article))
|
|
.route("/article/{id}", get(get_article))
|
|
.route("/article/{id}", post(update_article_route))
|
|
.route("/article/{id}", delete(delete_article_route))
|
|
.route("/article/{id}/variant", post(add_variant))
|
|
.route("/variant/{id}", post(update_variant_route))
|
|
.route("/variant/{id}", delete(delete_variant_route))
|
|
.route("/label", get(get_labels_route))
|
|
.route("/label", post(add_label_route))
|
|
.route("/label/{id}", post(update_label_route))
|
|
.route("/label/{id}", delete(delete_label_route))
|
|
.route("/settings", get(get_settings_route))
|
|
.route("/settings", post(update_settings_route))
|
|
.route("/supplier", get(get_suppliers_route))
|
|
.route("/supplier", post(add_supplier_route))
|
|
.route("/supplier/{id}", post(update_supplier_route))
|
|
.route("/supplier/{id}", delete(delete_supplier_route))
|
|
|
|
.with_state(pool)
|
|
.layer(cors);
|
|
|
|
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
|
|
info!("Server started on: {}", &addr);
|
|
|
|
axum::serve(listener, app).await.unwrap();
|
|
}
|
|
|
|
#[tracing::instrument(ret)]
|
|
async fn get_articles(
|
|
State(pool): State<PgPool>,
|
|
) -> (StatusCode, Json<Vec<Article>>) {
|
|
info!("Get all articles");
|
|
|
|
let result_articles: Option<Vec<Article>> = load_articles(pool).await;
|
|
|
|
match result_articles {
|
|
Some(articles) => {
|
|
(StatusCode::OK, Json(articles))
|
|
}
|
|
None => {
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(vec![]))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tracing::instrument(ret)]
|
|
async fn get_article(
|
|
Path(id): Path<i64>,
|
|
State(pool): State<PgPool>,
|
|
) -> (StatusCode, Json<Article>) {
|
|
info!("Get article with id: {}", id);
|
|
|
|
let result_article: Option<Article> = load_article(id, pool).await;
|
|
|
|
match result_article {
|
|
Some(article) => {
|
|
(StatusCode::OK, Json(article))
|
|
}
|
|
None => {
|
|
let article = Article {
|
|
id,
|
|
name: "".to_string(),
|
|
bio: false,
|
|
origin: Origin::EU,
|
|
description: None,
|
|
ingredients: None,
|
|
default_unit: Unit::G,
|
|
variants: vec![],
|
|
mhd: None,
|
|
bio_origin: None,
|
|
allergens_text: None,
|
|
bio_info: None,
|
|
topm_id: None,
|
|
additional_name: None,
|
|
};
|
|
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(article))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tracing::instrument(ret)]
|
|
async fn create_article(
|
|
State(pool): State<PgPool>,
|
|
Json(payload): Json<Article>,
|
|
) -> (StatusCode, Json<Article>) {
|
|
info!("Create article");
|
|
|
|
match insert_article(&payload, pool).await {
|
|
Some(article) => {
|
|
(StatusCode::CREATED, Json(article))
|
|
}
|
|
None => {
|
|
let article = Article {
|
|
id: 0,
|
|
name: "".to_string(),
|
|
bio: false,
|
|
origin: Origin::EU,
|
|
description: None,
|
|
ingredients: None,
|
|
default_unit: Unit::G,
|
|
variants: vec![],
|
|
mhd: None,
|
|
bio_origin: None,
|
|
allergens_text: None,
|
|
bio_info: None,
|
|
topm_id: None,
|
|
additional_name: None,
|
|
};
|
|
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(article))
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn update_article_route(
|
|
State(pool): State<PgPool>,
|
|
Path(article_id): Path<i64>,
|
|
Json(payload): Json<Article>,
|
|
) -> (StatusCode, Json<Article>) {
|
|
info!("Update article");
|
|
|
|
let update_article = update_article(article_id, &payload, pool).await;
|
|
|
|
match update_article {
|
|
Some(article) => {
|
|
(StatusCode::OK, Json(article))
|
|
}
|
|
None => {
|
|
let article = Article {
|
|
id: 0,
|
|
name: "".to_string(),
|
|
bio: false,
|
|
origin: Origin::EU,
|
|
description: None,
|
|
ingredients: None,
|
|
default_unit: Unit::G,
|
|
variants: vec![],
|
|
mhd: None,
|
|
bio_origin: None,
|
|
allergens_text: None,
|
|
bio_info: None,
|
|
topm_id: None,
|
|
additional_name: None,
|
|
};
|
|
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(article))
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn delete_article_route(
|
|
State(pool): State<PgPool>,
|
|
Path(article_id): Path<i64>,
|
|
) -> StatusCode {
|
|
info!("Delete article");
|
|
|
|
let delete_article_result = delete_article(article_id, pool).await;
|
|
|
|
match delete_article_result {
|
|
Some(_) => {
|
|
StatusCode::OK
|
|
}
|
|
None => {
|
|
StatusCode::INTERNAL_SERVER_ERROR
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
async fn add_variant(
|
|
State(pool): State<PgPool>,
|
|
Path(article_id): Path<i64>,
|
|
Json(payload): Json<Variant>,
|
|
) -> (StatusCode, Json<Variant>) {
|
|
info!("Add variant");
|
|
|
|
let created_variant = insert_variant(article_id, &payload, pool).await;
|
|
|
|
match created_variant {
|
|
Some(variant) => {
|
|
(StatusCode::OK, Json(variant))
|
|
}
|
|
None => {
|
|
let variant = Variant {
|
|
id: 0,
|
|
weight: "".to_string(),
|
|
ean: None,
|
|
name: None,
|
|
description: None,
|
|
ingredients: None,
|
|
unit: Unit::G,
|
|
label: None,
|
|
variant_description: None,
|
|
topm_row: None,
|
|
};
|
|
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(variant))
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn update_variant_route(
|
|
State(pool): State<PgPool>,
|
|
Path(variant_id): Path<i64>,
|
|
Json(payload): Json<Variant>,
|
|
) -> (StatusCode, Json<Variant>) {
|
|
info!("Update variant");
|
|
|
|
let update_variant = update_variant(variant_id, &payload, pool).await;
|
|
|
|
match update_variant {
|
|
Some(variant) => {
|
|
(StatusCode::OK, Json(variant))
|
|
}
|
|
None => {
|
|
let variant = Variant {
|
|
id: 0,
|
|
weight: "".to_string(),
|
|
ean: None,
|
|
name: None,
|
|
description: None,
|
|
ingredients: None,
|
|
unit: Unit::G,
|
|
label: None,
|
|
variant_description: None,
|
|
topm_row: None,
|
|
};
|
|
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(variant))
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn delete_variant_route(
|
|
State(pool): State<PgPool>,
|
|
Path(variant_id): Path<i64>,
|
|
) -> StatusCode {
|
|
info!("Delete variant");
|
|
|
|
let delete_variant_result = delete_variant(variant_id, pool).await;
|
|
|
|
match delete_variant_result {
|
|
Some(_) => {
|
|
StatusCode::OK
|
|
}
|
|
None => {
|
|
StatusCode::INTERNAL_SERVER_ERROR
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tracing::instrument(ret)]
|
|
async fn get_labels_route(
|
|
State(pool): State<PgPool>,
|
|
) -> (StatusCode, Json<Vec<Label>>) {
|
|
info!("Get all labels");
|
|
|
|
match load_labels(pool).await {
|
|
Some(labels) => {
|
|
(StatusCode::OK, Json(labels))
|
|
}
|
|
None => {
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(vec![]))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tracing::instrument(ret)]
|
|
async fn add_label_route(
|
|
State(pool): State<PgPool>,
|
|
Json(payload): Json<Label>,
|
|
) -> (StatusCode, Json<Label>) {
|
|
info!("Add label");
|
|
|
|
match insert_label(&payload, pool).await {
|
|
Some(variant) => {
|
|
(StatusCode::OK, Json(variant))
|
|
}
|
|
None => {
|
|
let label = Label {
|
|
id: 0,
|
|
name: "".to_string(),
|
|
};
|
|
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(label))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tracing::instrument(ret)]
|
|
async fn update_label_route(
|
|
State(pool): State<PgPool>,
|
|
Path(label_id): Path<i64>,
|
|
Json(payload): Json<Label>,
|
|
) -> (StatusCode, Json<Label>) {
|
|
info!("Update label");
|
|
|
|
match update_label(label_id, &payload, pool).await {
|
|
Some(variant) => {
|
|
(StatusCode::OK, Json(variant))
|
|
}
|
|
None => {
|
|
let label = Label {
|
|
id: 0,
|
|
name: "".to_string(),
|
|
};
|
|
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(label))
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn delete_label_route(
|
|
State(pool): State<PgPool>,
|
|
Path(label_id): Path<i64>,
|
|
) -> StatusCode {
|
|
info!("Delete label");
|
|
|
|
let delete_variant_result = delete_label(label_id, pool).await;
|
|
|
|
match delete_variant_result {
|
|
Some(_) => {
|
|
StatusCode::OK
|
|
}
|
|
None => {
|
|
StatusCode::INTERNAL_SERVER_ERROR
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tracing::instrument(ret)]
|
|
async fn get_settings_route(
|
|
State(pool): State<PgPool>,
|
|
) -> (StatusCode, Json<Settings>) {
|
|
info!("Get settings");
|
|
|
|
match load_settings(&pool).await {
|
|
Some(settings) => {
|
|
(StatusCode::OK, Json(settings))
|
|
}
|
|
None => {
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(
|
|
Settings {
|
|
id: 0,
|
|
mhd: "".to_string(),
|
|
bio: "".to_string(),
|
|
allergens_text: "".to_string(),
|
|
bio_info: "".to_string(),
|
|
}
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tracing::instrument(ret)]
|
|
async fn update_settings_route(
|
|
State(pool): State<PgPool>,
|
|
Json(payload): Json<Settings>,
|
|
) -> (StatusCode, Json<Settings>) {
|
|
info!("Update settings");
|
|
|
|
match update_settings(&payload, pool).await {
|
|
Some(settings) => {
|
|
(StatusCode::OK, Json(settings))
|
|
}
|
|
None => {
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(
|
|
Settings {
|
|
id: 0,
|
|
mhd: "".to_string(),
|
|
bio: "".to_string(),
|
|
allergens_text: "".to_string(),
|
|
bio_info: "".to_string(),
|
|
}
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tracing::instrument(ret)]
|
|
async fn get_suppliers_route(
|
|
State(pool): State<PgPool>,
|
|
) -> (StatusCode, Json<Vec<Supplier>>) {
|
|
info!("Get all suppliers");
|
|
|
|
match load_suppliers(pool).await {
|
|
Some(suppliers) => {
|
|
(StatusCode::OK, Json(suppliers))
|
|
}
|
|
None => {
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(vec![]))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tracing::instrument(ret)]
|
|
async fn add_supplier_route(
|
|
State(pool): State<PgPool>,
|
|
Json(payload): Json<Supplier>,
|
|
) -> (StatusCode, Json<Supplier>) {
|
|
info!("Add supplier");
|
|
|
|
match insert_supplier(&payload, pool).await {
|
|
Some(supplier) => {
|
|
(StatusCode::OK, Json(supplier))
|
|
}
|
|
None => {
|
|
let supplier = Supplier {
|
|
id: 0,
|
|
topm_id: "".to_string(),
|
|
name: "".to_string(),
|
|
bio_info: None,
|
|
};
|
|
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(supplier))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tracing::instrument(ret)]
|
|
async fn update_supplier_route(
|
|
State(pool): State<PgPool>,
|
|
Path(supplier_id): Path<i64>,
|
|
Json(payload): Json<Supplier>,
|
|
) -> (StatusCode, Json<Supplier>) {
|
|
info!("Update supplier");
|
|
|
|
match update_supplier(supplier_id, &payload, pool).await {
|
|
Some(supplier) => {
|
|
(StatusCode::OK, Json(supplier))
|
|
}
|
|
None => {
|
|
let supplier = Supplier {
|
|
id: 0,
|
|
topm_id: "".to_string(),
|
|
name: "".to_string(),
|
|
bio_info: None,
|
|
};
|
|
|
|
(StatusCode::INTERNAL_SERVER_ERROR, Json(supplier))
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn delete_supplier_route(
|
|
State(pool): State<PgPool>,
|
|
Path(supplier_id): Path<i64>,
|
|
) -> StatusCode {
|
|
info!("Delete supplier");
|
|
|
|
let deleted_result = delete_supplier(supplier_id, pool).await;
|
|
|
|
match deleted_result {
|
|
Some(_) => {
|
|
StatusCode::OK
|
|
}
|
|
None => {
|
|
StatusCode::INTERNAL_SERVER_ERROR
|
|
}
|
|
}
|
|
}
|