Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
Commit 466d07b1 authored by Pierre Jarriges's avatar Pierre Jarriges
Browse files

wip:create static view when create article

parent bbd29ec7
No related branches found
No related tags found
1 merge request!1Dev
......@@ -5,4 +5,5 @@ bundle.js
node_modules
target
.env
public/**/*.js
\ No newline at end of file
public/**/*.js
public/**/view/*
\ No newline at end of file
......@@ -12,6 +12,7 @@ class Article {
this.images = [];
this.body = "";
this.locale = "";
this.display_priority_index = 1;
}
}
......
......@@ -11,25 +11,6 @@ async function fetch_article(article_id) {
})
}
async function fetch_article_by_title(article_title) {
const form_data = new FormData();
form_data.append("title", article_title);
return new Promise((resolve, reject) => {
fetch(`/article-by-title/`, {
method: "POST",
body: new URLSearchParams(form_data),
}).then(async res => {
if (res.status >= 400 && res.status < 600) {
const text = await res.text();
reject(text);
} else {
resolve(await res.json());
}
}).catch(e => reject(e))
})
}
async function fetch_articles_by_category(category) {
return new Promise((resolve, reject) => {
fetch(`/articles/${category}`).then(async res => {
......@@ -126,7 +107,6 @@ async function fetch_all_articles() {
module.exports = {
fetch_article,
fetch_article_by_title,
fetch_articles_by_category,
fetch_post_article,
fetch_update_article,
......
......@@ -14,7 +14,7 @@ services:
volumes:
- ./src:/usr/src/kuadrado_server/src:ro
- ./Cargo.toml:/usr/src/kuadrado_server/Cargo.toml:ro
- ./public:${RESOURCES_DIR}/public:ro
- ./public:${RESOURCES_DIR}/public
- /etc/letsencrypt/:${RESOURCES_DIR}/certs:ro
command: cargo run
env_file:
......@@ -34,3 +34,7 @@ services:
- ./mongo/scripts:/mongo-scripts
ports:
- "27017-27019:27017-27019"
deploy:
resources:
limits:
memory: 250M
......@@ -31,3 +31,7 @@ services:
- ./mongo/scripts:/mongo-scripts
ports:
- "27017-27019:27017-27019"
deploy:
resources:
limits:
memory: 250M
......@@ -12,6 +12,7 @@ pub struct Env {
pub crypt_key: String,
pub default_admin_username: String,
pub default_admin_password: String,
pub public_dir: std::path::PathBuf,
}
static RELEASE_MODES: [&str; 3] = ["debug", "test", "prod"];
......@@ -54,6 +55,10 @@ impl Env {
.expect("DEFAULT_ADMIN_USERNAME is not defined"),
default_admin_password: env::var("DEFAULT_ADMIN_PASSWORD")
.expect("DEFAULT_ADMIN_PASSWORD is not defined"),
public_dir: std::path::PathBuf::from(
env::var("RESOURCES_DIR").expect("RESOURCES_DIR is not defined"),
)
.join("public"),
}
}
......@@ -72,6 +77,10 @@ impl Env {
.expect("DEFAULT_ADMIN_USERNAME is not defined"),
default_admin_password: env::var("DEFAULT_ADMIN_PASSWORD")
.expect("DEFAULT_ADMIN_PASSWORD is not defined"),
public_dir: std::path::PathBuf::from(
env::var("RESOURCES_DIR").expect("RESOURCES_DIR is not defined"),
)
.join("public"),
}
}
}
......@@ -7,6 +7,7 @@ mod middleware;
mod model;
mod service;
mod standard_static_files;
mod static_view;
mod tls;
mod view;
mod view_resource;
......@@ -34,10 +35,6 @@ async fn main() -> std::io::Result<()> {
let server_port = env_var("SERVER_PORT").expect("SERVER_PORT is not defined.");
let server_port_tls = env_var("SERVER_PORT_TLS").expect("SERVER_PORT_TLS is not defined.");
let public_dir =
std::path::PathBuf::from(env_var("RESOURCES_DIR").expect("RESOURCES_DIR is not defined"))
.join("public");
let app_state = AppState::with_default_admin_user().await;
HttpServer::new(move || {
......@@ -89,7 +86,6 @@ async fn main() -> std::io::Result<()> {
.service(delete_article)
.service(get_articles_by_category)
.service(get_article)
.service(get_article_by_title)
.service(get_all_articles)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// STANDARD FILES ///////////////////////////////////////////////////////////////////////////////////////////
......@@ -102,18 +98,18 @@ async fn main() -> std::io::Result<()> {
scope("/v")
.service(Files::new(
"/admin-panel/assets",
public_dir.join("views/admin-panel/assets"),
app_state.env.public_dir.join("views/admin-panel/assets"),
))
.service(Files::new(
"/admin-login/assets",
public_dir.join("views/admin-login/assets"),
app_state.env.public_dir.join("views/admin-login/assets"),
))
// get_view will match any url to we put it at last
.service(get_view),
)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC WEBSITE //////////////////////////////////////////////////////////////////////////////////////////////
.service(Files::new("/", &public_dir).index_file("index.html"))
.service(Files::new("/", &app_state.env.public_dir).index_file("index.html"))
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// empty 404 ////////////////////////////////////////////////////////////////////////////////////////////////
.default_service(to(|| {
......
use crate::{middleware::AuthenticatedAdminMiddleware, model::Article, AppState};
use crate::{
middleware::AuthenticatedAdminMiddleware, model::Article, static_view::create_static_view,
AppState,
};
use actix_web::{
delete, get, post, put,
web::{Data, Form, Json, Path},
web::{Data, Json, Path},
HttpRequest, HttpResponse, Responder,
};
use chrono::Utc;
use futures::stream::StreamExt;
use serde::{Deserialize, Serialize};
use wither::{
bson::{doc, oid::ObjectId, DateTime},
bson::{doc, oid::ObjectId, Bson, DateTime},
mongodb::Collection,
prelude::Model,
};
......@@ -22,6 +25,38 @@ fn get_collection(app_state: &AppState) -> Collection<Article> {
app_state.db.collection_with_type::<Article>("articles")
}
async fn generate_article_view(app_state: &AppState, id: &ObjectId) -> Result<(), String> {
match Article::find_one(&app_state.db, doc! {"_id":&id}, None).await {
Ok(art) => {
if art.is_none() {
return Err(format!("Article with id {} was not found", id));
}
let art = art.unwrap();
let html = format!(
"
<html lang='{}'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<meta name='description' content='{}'>
<title>{}</title>
</head>
<body>
<div>{}<div>
</body>
</html>
",
art.locale, art.subtitle, art.title, art.body,
);
create_static_view(&app_state, art.category, art.title, html)
}
Err(e) => return Err(format!("ERR {}", e)),
}
}
#[post("/post-article")]
pub async fn post_article(
app_state: Data<AppState>,
......@@ -40,7 +75,20 @@ pub async fn post_article(
.insert_one(article_data, None)
.await
{
Ok(res) => HttpResponse::Created().json(res),
Ok(res) => {
match &res.inserted_id {
Bson::ObjectId(id) => {
if let Err(e) = generate_article_view(&app_state, id).await {
return HttpResponse::InternalServerError()
.body(format!("Error creating article page {:?}", e));
}
}
_ => {
return HttpResponse::InternalServerError().body("Error creating article page")
}
}
HttpResponse::Created().json(res)
}
Err(e) => {
HttpResponse::InternalServerError().body(format!("Error inserting new article {:?}", e))
}
......@@ -159,24 +207,6 @@ pub async fn get_article(app_state: Data<AppState>, article_id: Path<String>) ->
}
}
#[post("/article-by-title")]
pub async fn get_article_by_title(
app_state: Data<AppState>,
form_data: Form<ArticleTitleFormData>,
) -> impl Responder {
let title = form_data.into_inner().title;
match Article::find_one(&app_state.db, doc! {"title":title}, None).await {
Ok(art) => {
if art.is_none() {
return HttpResponse::NotFound().body("Article was not found");
}
HttpResponse::Ok().json(art)
}
Err(e) => HttpResponse::InternalServerError().body(format!("Database error: {:#?}", e)),
}
}
#[get("/articles")]
pub async fn get_all_articles(app_state: Data<AppState>) -> impl Responder {
match get_collection(&app_state).find(None, None).await {
......@@ -221,7 +251,6 @@ mod test_articles {
web::Bytes,
App,
};
use wither::bson::Bson;
async fn insert_test_article(
app_state: &AppState,
......@@ -558,42 +587,6 @@ mod test_articles {
assert_eq!(del_count, 1);
}
#[tokio::test]
async fn test_get_article_by_title() {
dotenv::dotenv().ok();
let app_state = AppState::for_test().await;
let mut app = test::init_service(
App::new()
.app_data(Data::new(app_state.clone()))
.service(get_article_by_title),
)
.await;
let article = Article::test_article();
let (article_id, article_title) = insert_test_article(&app_state, article.clone())
.await
.unwrap();
let req = test::TestRequest::with_uri("/article-by-title")
.header("Accept", "application/json")
.method(Method::POST)
.set_form(&ArticleTitleFormData {
title: article_title.to_owned(),
})
.to_request();
let resp = test::call_service(&mut app, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let result: Article = test::read_body_json(resp).await;
assert_eq!(result.title, article_title);
let del_count = delete_test_article(&app_state, &article_id).await.unwrap();
assert_eq!(del_count, 1);
}
#[tokio::test]
async fn test_get_articles_by_category() {
dotenv::dotenv().ok();
......
use crate::app_state::AppState;
use std::fs::{create_dir, create_dir_all, File};
use std::io::Write;
pub fn create_static_view(
app_state: &AppState,
category: String,
filename: String,
html: String,
) -> Result<(), String> {
let view_path = app_state.env.public_dir.join(&category).join("view");
if !view_path.exists() {
if let Err(e) = create_dir(&view_path) {
return Err(format!("Couldn't create directory {:?}: {}", view_path, e));
}
}
let d_path = app_state
.env
.public_dir
.join(&category)
.join("view")
.join(&filename);
if let Err(e) = create_dir_all(&d_path) {
return Err(format!("Error creating directory {:?} : {}", d_path, e));
}
let f_path = d_path.join("index.html");
match File::create(&f_path) {
Ok(mut f) => {
if let Err(e) = f.write_all(html.as_bytes()) {
return Err(format!("Error writing to {:?} : {}", f_path, e));
}
Ok(())
}
Err(e) => Err(format!("Error creating {:?} : {}", f_path, e)),
}
}
......@@ -61,7 +61,7 @@ impl ViewResourceManager {
let path: PathBuf = format!("{}/{}", dir_path.to_str().unwrap(), desc.index_file_name)
.parse()
.expect(&format!(
"Failed to pare resource index file path {:?}",
"Failed to parse resource index file path {:?}",
desc.index_file_name
));
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment