feat: tera template
This commit is contained in:
parent
df0edc4435
commit
89ae721a90
@ -13,12 +13,13 @@ r2d2 = "0.8"
|
||||
lazy_static = "1.1"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
tera = "*"
|
||||
tera = "0.11.0"
|
||||
pulldown-cmark = { version = "0.1.2", default-features = false }
|
||||
chrono = { version = "*", features = ["serde"] }
|
||||
rust-crypto = "^0.2"
|
||||
rss = "1.6.1"
|
||||
|
||||
actix-web="1.0.0-alpha.6"
|
||||
actix-web= "1.0.0-alpha.6"
|
||||
actix-files = "0.1.0-alpha.6"
|
||||
actix = "0.8.1"
|
||||
diesel_migrations = "1.4.0"
|
||||
|
27
src/main.rs
27
src/main.rs
@ -13,6 +13,9 @@ use actix_web::{
|
||||
use dotenv::dotenv;
|
||||
|
||||
use crate::pg_pool::database_pool_establish;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use tera::compile_templates;
|
||||
|
||||
mod guard;
|
||||
mod models;
|
||||
@ -21,28 +24,38 @@ mod request;
|
||||
mod response;
|
||||
mod routers;
|
||||
mod schema;
|
||||
mod template;
|
||||
mod view;
|
||||
|
||||
embed_migrations!();
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let sys = actix::System::new("lemmy");
|
||||
dotenv().ok();
|
||||
// let sys = actix::System::new("lemmy");
|
||||
|
||||
let database_url = std::env::var("DATABASE_URL").expect("database_url must be set");
|
||||
let pool = database_pool_establish(&database_url);
|
||||
|
||||
let tera = Arc::new(compile_templates!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/templates/**/*.html"
|
||||
)));
|
||||
|
||||
embedded_migrations::run(&pool.get().expect("cannot get connection"));
|
||||
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.data(pool.clone())
|
||||
.data(tera.clone())
|
||||
.wrap(Logger::default())
|
||||
.wrap(Cors::default())
|
||||
.default_service(web::route().to(|| "hello world"))
|
||||
.service(routers::article::homepage)
|
||||
.service(actix_files::Files::new(
|
||||
"/statics",
|
||||
"./templates/resources/",
|
||||
))
|
||||
})
|
||||
.bind(("127.0.0.1", 8000))?
|
||||
.system_exit()
|
||||
.start();
|
||||
|
||||
sys.run();
|
||||
Ok(())
|
||||
// .system_exit()
|
||||
.run()
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ impl CRUD<NewArticle, NewArticle, i32> for Article {
|
||||
fn read(conn: &PgConnection) -> Vec<Self> {
|
||||
articles::table
|
||||
.order(articles::publish_at.desc())
|
||||
.load::<Article>(conn)
|
||||
.load::<Self>(conn)
|
||||
.expect("something wrong")
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@ use diesel::prelude::*;
|
||||
use diesel::result::Error;
|
||||
use diesel::{AsChangeset, Insertable, Queryable};
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Queryable, Debug, Serialize, Insertable, AsChangeset)]
|
||||
#[table_name = "setting"]
|
||||
pub struct Setting {
|
||||
@ -12,6 +14,43 @@ pub struct Setting {
|
||||
pub value: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct SettingMap {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub url: String,
|
||||
pub analysis: String,
|
||||
}
|
||||
|
||||
impl Setting {
|
||||
pub fn load(conn: &PgConnection) -> SettingMap {
|
||||
let settings = setting::table.load::<Setting>(conn).unwrap();
|
||||
|
||||
let mut settings_map: HashMap<String, String> = HashMap::new();
|
||||
|
||||
for one_setting in settings {
|
||||
settings_map.insert(
|
||||
one_setting.name,
|
||||
one_setting.value.unwrap_or("".to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
SettingMap {
|
||||
title: settings_map.get("title").unwrap_or(&"".to_string()).clone(),
|
||||
description: settings_map
|
||||
.get("description")
|
||||
.unwrap_or(&"".to_string())
|
||||
.clone(),
|
||||
|
||||
url: settings_map.get("url").unwrap_or(&"".to_string()).clone(),
|
||||
analysis: settings_map
|
||||
.get("analysis")
|
||||
.unwrap_or(&"".to_string())
|
||||
.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CRUD<(), Setting, String> for Setting {
|
||||
fn create(conn: &PgConnection, from: &()) -> Result<Self, Error> {
|
||||
unimplemented!()
|
||||
|
@ -26,6 +26,32 @@
|
||||
//
|
||||
// Template::render("index", &context)
|
||||
//}
|
||||
|
||||
use crate::models::article::Article;
|
||||
use crate::models::setting::Setting;
|
||||
use crate::models::CRUD;
|
||||
use crate::pg_pool::Pool;
|
||||
use crate::view::article::ArticleView;
|
||||
use actix_web::{get, web, HttpResponse, Responder};
|
||||
use std::sync::Arc;
|
||||
use tera::{Context, Tera};
|
||||
|
||||
#[get("/")]
|
||||
pub fn homepage(tera: web::Data<Arc<Tera>>, conn: web::Data<Pool>) -> impl Responder {
|
||||
let connection = conn.get().unwrap();
|
||||
let vec = Article::read(&connection);
|
||||
|
||||
let articles: Vec<ArticleView> = vec.iter().map(ArticleView::from).collect();
|
||||
let settings = Setting::load(&connection);
|
||||
|
||||
let mut context = Context::new();
|
||||
context.insert("setting", &settings);
|
||||
context.insert("articles", &articles);
|
||||
HttpResponse::Ok()
|
||||
.content_type("text/html")
|
||||
.body(tera.render("homepage.html", &context).unwrap())
|
||||
}
|
||||
|
||||
//
|
||||
////#[get("/archives/<archives_id>")]
|
||||
//pub fn single_article(setting: SettingMap, conn: DbConn, archives_id: i32) -> Result<Template, Status> {
|
||||
@ -49,7 +75,7 @@
|
||||
//
|
||||
////#[get("/statics/<file..>")]
|
||||
//pub fn static_content(file: PathBuf) -> Result<NamedFile, Status> {
|
||||
// let path = Path::new("static/resources/").join(file);
|
||||
// let path = Path::new("templates/resources/").join(file);
|
||||
// let result = NamedFile::open(&path);
|
||||
// if let Ok(file) = result {
|
||||
// Ok(file)
|
||||
|
@ -1,4 +1,4 @@
|
||||
//pub mod article;
|
||||
pub mod article;
|
||||
//pub mod admin;
|
||||
//pub mod rss;
|
||||
//pub mod catacher;
|
||||
|
1
src/template.rs
Normal file
1
src/template.rs
Normal file
@ -0,0 +1 @@
|
||||
|
30
src/view/article.rs
Normal file
30
src/view/article.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use crate::models::article::Article;
|
||||
use pulldown_cmark::html;
|
||||
use pulldown_cmark::Parser;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ArticleView<'a> {
|
||||
pub article: &'a Article,
|
||||
pub timestamp: i64,
|
||||
pub markdown_content: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
impl<'a> ArticleView<'a> {
|
||||
pub fn from(article: &'a Article) -> ArticleView {
|
||||
let content_split: Vec<_> = article.body.split("<!--more-->").collect();
|
||||
let description_parser = Parser::new(&content_split[0]);
|
||||
let parser = Parser::new(&article.body);
|
||||
let mut description_buf = String::new();
|
||||
let mut content_buf = String::new();
|
||||
html::push_html(&mut content_buf, parser);
|
||||
html::push_html(&mut description_buf, description_parser);
|
||||
ArticleView {
|
||||
article,
|
||||
timestamp: article.publish_at.timestamp(),
|
||||
markdown_content: content_buf,
|
||||
description: description_buf,
|
||||
}
|
||||
}
|
||||
}
|
1
src/view/mod.rs
Normal file
1
src/view/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod article;
|
@ -1,4 +1,4 @@
|
||||
{% extends "base" %}
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ setting.title }}{% endblock title %}
|
||||
|
||||
@ -12,15 +12,15 @@
|
||||
</header>
|
||||
|
||||
<section class="container">
|
||||
{% for article in articles %}
|
||||
{% for article in articles %}
|
||||
<section class="article">
|
||||
<p class="mate">{{ article.timestamp | date(format="%B %d, %Y") }}</p>
|
||||
<a class="title" href="{% if article.article.url %}{{ article.article.url }}{% else %}archives/{{ article.article.id }}{% endif %}">{{ article.article.title }}</a>
|
||||
<section class="yue desc">
|
||||
{{ article.description }}
|
||||
{{ article.description|safe }}
|
||||
</section>
|
||||
</section>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
</section>
|
Loading…
Reference in New Issue
Block a user