feat: combine app data into rubble data

This commit is contained in:
Kilerd Chan 2019-04-22 14:47:50 +08:00
parent 41d3c21404
commit a9836cf0c3
6 changed files with 81 additions and 93 deletions

21
src/data.rs Normal file
View File

@ -0,0 +1,21 @@
use crate::pg_pool::{ManagedPgConn, Pool};
use diesel::prelude::PgConnection;
use r2d2::PooledConnection;
use std::sync::Arc;
use tera::{Context, Tera};
#[derive(Clone)]
pub struct RubbleData {
pub pool: Pool,
pub tera: Arc<Tera>,
}
impl RubbleData {
pub fn postgres(&self) -> PooledConnection<ManagedPgConn> {
let pool = self.pool.clone();
pool.get().unwrap()
}
pub fn render(&self, template_name: &str, data: &Context) -> String {
self.tera.render(template_name, data).unwrap()
}
}

View File

@ -16,6 +16,7 @@ use actix_web::{
use dotenv::dotenv;
use crate::data::RubbleData;
use crate::pg_pool::database_pool_establish;
use actix_web::web::route;
use rand::prelude::*;
@ -24,6 +25,7 @@ use std::sync::Arc;
use tera::compile_templates;
use time::Duration;
mod data;
mod models;
mod pg_pool;
mod routers;
@ -38,18 +40,18 @@ fn main() {
pretty_env_logger::init();
let database_url = std::env::var("DATABASE_URL").expect("database_url must be set");
let pool = database_pool_establish(&database_url);
embedded_migrations::run(&pool.get().expect("cannot get connection"));
let tera = Arc::new(compile_templates!("templates/**/*.html"));
let random_cookie_key: Vec<u8> = (0..32).map(|_| rand::random::<u8>()).collect();
let data = RubbleData {
pool: database_pool_establish(&database_url),
tera: Arc::new(compile_templates!("templates/**/*.html")),
};
embedded_migrations::run(&data.pool.get().expect("cannot get connection"));
HttpServer::new(move || {
App::new()
.data(pool.clone())
.data(tera.clone())
.data(data.clone())
.wrap(Logger::default())
.wrap(Cors::default())
.wrap(IdentityService::new(

View File

@ -3,7 +3,7 @@ use diesel::r2d2::ConnectionManager;
use r2d2;
use std::ops::Deref;
type ManagedPgConn = ConnectionManager<PgConnection>;
pub type ManagedPgConn = ConnectionManager<PgConnection>;
pub type Pool = r2d2::Pool<ManagedPgConn>;

View File

@ -1,5 +1,6 @@
use crate::models::article::{Article, NewArticle};
use crate::data::RubbleData;
use crate::models::setting::Setting;
use crate::models::user::User;
use crate::models::CRUD;
@ -29,21 +30,15 @@ pub fn redirect_to_admin_panel() -> impl Responder {
}
#[get("/panel")]
pub fn admin_panel(
id: Identity,
tera: web::Data<Arc<Tera>>,
conn: web::Data<Pool>,
) -> impl Responder {
let connection = conn.get().unwrap();
pub fn admin_panel(id: Identity, data: web::Data<RubbleData>) -> impl Responder {
if id.identity().is_none() {
return RubbleResponder::Redirect("/admin/login".into());
}
let articles = Article::read(&connection);
let settings = Setting::load(&connection);
let articles = Article::read(&data.postgres());
let settings = Setting::load(&data.postgres());
let admin = User::find_by_username(&*connection, &id.identity().unwrap())
let admin = User::find_by_username(&data.postgres(), &id.identity().unwrap())
.expect("cannot found this user");
let mut context = Context::new();
@ -51,14 +46,14 @@ pub fn admin_panel(
context.insert("articles", &articles);
context.insert("admin", &admin);
RubbleResponder::Html(tera.render("admin/panel.html", &context).unwrap())
RubbleResponder::Html(data.render("admin/panel.html", &context))
}
#[get("/login")]
pub fn admin_login(id: Identity, tera: web::Data<Arc<Tera>>) -> impl Responder {
pub fn admin_login(id: Identity, data: web::Data<RubbleData>) -> impl Responder {
match id.identity() {
Some(_) => RubbleResponder::Redirect("/admin/panel".into()),
None => RubbleResponder::Html(tera.render("admin/login.html", &Context::new()).unwrap()),
None => RubbleResponder::Html(data.render("admin/login.html", &Context::new())),
}
}
@ -66,11 +61,9 @@ pub fn admin_login(id: Identity, tera: web::Data<Arc<Tera>>) -> impl Responder {
pub fn admin_authentication(
id: Identity,
user: Form<LoginForm>,
conn: web::Data<Pool>,
data: web::Data<RubbleData>,
) -> impl Responder {
let connection = conn.get().unwrap();
let fetched_user = User::find_by_username(&connection, &user.username);
let fetched_user = User::find_by_username(&data.postgres(), &user.username);
match fetched_user {
Ok(login_user) => {
@ -87,17 +80,12 @@ pub fn admin_authentication(
}
#[get("/article/new")]
pub fn article_creation(
id: Identity,
tera: web::Data<Arc<Tera>>,
conn: web::Data<Pool>,
) -> impl Responder {
pub fn article_creation(id: Identity, data: web::Data<RubbleData>) -> impl Responder {
if id.identity().is_none() {
return RubbleResponder::Redirect("/admin/login".into());
}
let connection = conn.get().unwrap();
let admin = User::find_by_username(&*connection, &id.identity().unwrap())
let admin = User::find_by_username(&data.postgres(), &id.identity().unwrap())
.expect("cannot found this user");
let mut context = Context::new();
@ -113,31 +101,29 @@ pub fn article_creation(
};
context.insert("article", &article);
RubbleResponder::Html(tera.render("admin/article_add.html", &context).unwrap())
RubbleResponder::Html(data.render("admin/article_add.html", &context))
}
#[get("/article/{article_id}")]
pub fn article_edit(
id: Identity,
article_id: web::Path<i32>,
tera: web::Data<Arc<Tera>>,
conn: web::Data<Pool>,
data: web::Data<RubbleData>,
) -> impl Responder {
if id.identity().is_none() {
return RubbleResponder::Redirect("/admin/login".into());
}
let connection = conn.get().unwrap();
let admin = User::find_by_username(&*connection, &id.identity().unwrap())
let admin = User::find_by_username(&data.postgres(), &id.identity().unwrap())
.expect("cannot found this user");
let result = Article::get_by_pk(&connection, article_id.into_inner());
let result = Article::get_by_pk(&data.postgres(), article_id.into_inner());
match result {
Ok(article) => {
let mut context = Context::new();
context.insert("article", &article);
RubbleResponder::Html(tera.render("admin/article_add.html", &context).unwrap())
RubbleResponder::Html(data.render("admin/article_add.html", &context))
}
Err(_) => RubbleResponder::Redirect("/admin/panel".into()),
}
@ -146,22 +132,20 @@ pub fn article_edit(
#[post("/article")]
pub fn article_save(
id: Identity,
tera: web::Data<Arc<Tera>>,
conn: web::Data<Pool>,
article: Form<NewArticle>,
data: web::Data<RubbleData>,
) -> impl Responder {
if id.identity().is_none() {
return RubbleResponder::Redirect("/admin/login".into());
}
let connection = conn.get().unwrap();
let admin = User::find_by_username(&*connection, &id.identity().unwrap())
let admin = User::find_by_username(&data.postgres(), &id.identity().unwrap())
.expect("cannot found this user");
let res = if let Some(article_id) = article.id {
Article::update(&connection, article_id, &article)
Article::update(&data.postgres(), article_id, &article)
} else {
Article::create(&connection, &article)
Article::create(&data.postgres(), &article)
};
RubbleResponder::Redirect("/admin/panel".into())
}
@ -169,17 +153,16 @@ pub fn article_save(
pub fn article_deletion(
id: Identity,
article_id: web::Path<i32>,
conn: web::Data<Pool>,
data: web::Data<RubbleData>,
) -> impl Responder {
if id.identity().is_none() {
return RubbleResponder::Redirect("/admin/login".into());
}
let connection = conn.get().unwrap();
let admin = User::find_by_username(&*connection, &id.identity().unwrap())
let admin = User::find_by_username(&data.postgres(), &id.identity().unwrap())
.expect("cannot found this user");
Article::delete(&connection, article_id.into_inner());
Article::delete(&data.postgres(), article_id.into_inner());
RubbleResponder::Redirect("/admin/panel".into())
}
@ -187,17 +170,16 @@ pub fn article_deletion(
pub fn change_password(
id: Identity,
password: web::Form<NewPassword>,
conn: web::Data<Pool>,
data: web::Data<RubbleData>,
) -> impl Responder {
if id.identity().is_none() {
return RubbleResponder::Redirect("/admin/login".into());
}
let connection = conn.get().unwrap();
let mut admin = User::find_by_username(&*connection, &id.identity().unwrap())
let mut admin = User::find_by_username(&data.postgres(), &id.identity().unwrap())
.expect("cannot found this user");
admin.password = User::password_generate(&password.password).to_string();
User::update(&connection, admin.id, &admin);
User::update(&data.postgres(), admin.id, &admin);
id.forget();
RubbleResponder::Redirect("/admin/panel".into())
}
@ -206,17 +188,16 @@ pub fn change_password(
pub fn change_setting(
id: Identity,
setting: web::Form<Setting>,
conn: web::Data<Pool>,
data: web::Data<RubbleData>,
) -> impl Responder {
if id.identity().is_none() {
return RubbleResponder::Redirect("/admin/login".into());
}
let connection = conn.get().unwrap();
let mut admin = User::find_by_username(&*connection, &id.identity().unwrap())
let mut admin = User::find_by_username(&data.postgres(), &id.identity().unwrap())
.expect("cannot found this user");
Setting::update(&connection, setting.name.clone(), &setting);
Setting::update(&data.postgres(), setting.name.clone(), &setting);
RubbleResponder::Redirect("/admin/panel".into())
}

View File

@ -1,3 +1,4 @@
use crate::data::RubbleData;
use crate::models::article::Article;
use crate::models::setting::Setting;
use crate::models::CRUD;
@ -9,34 +10,26 @@ 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: Vec<Article> = Article::read(&connection);
pub fn homepage(data: web::Data<RubbleData>) -> impl Responder {
let vec: Vec<Article> = Article::read(&data.postgres());
let article_view: Vec<_> = vec
.iter()
.filter(|article| article.published == true)
.map(ArticleView::from)
.collect();
// let articles: Vec<ArticleView> = vec.iter().map(ArticleView::from).collect();
let settings = Setting::load(&connection);
let settings = Setting::load(&data.postgres());
let mut context = Context::new();
context.insert("setting", &settings);
context.insert("articles", &article_view);
RubbleResponder::Html(tera.render("homepage.html", &context).unwrap())
RubbleResponder::Html(data.render("homepage.html", &context))
}
#[get("/archives/{archives_id}")]
pub fn single_article(
archives_id: web::Path<i32>,
tera: web::Data<Arc<Tera>>,
conn: web::Data<Pool>,
) -> impl Responder {
let connection = conn.get().unwrap();
let article = Article::get_by_pk(&connection, archives_id.into_inner());
pub fn single_article(archives_id: web::Path<i32>, data: web::Data<RubbleData>) -> impl Responder {
let article = Article::get_by_pk(&data.postgres(), archives_id.into_inner());
if let Err(e) = article {
return RubbleResponder::NotFound;
@ -44,30 +37,25 @@ pub fn single_article(
let article1 = article.unwrap();
if let Some(ref to) = article1.url {
if to.len()!= 0 {
if to.len() != 0 {
return RubbleResponder::Redirect(format!("/{}", to));
}
}
let view = ArticleView::from(&article1);
let settings = Setting::load(&connection);
let settings = Setting::load(&data.postgres());
let mut context = Context::new();
context.insert("setting", &settings);
context.insert("article", &view);
RubbleResponder::Html(tera.render("archives.html", &context).unwrap())
RubbleResponder::Html(data.render("archives.html", &context))
}
#[get("/{url}")]
pub fn get_article_by_url(
url: web::Path<String>,
tera: web::Data<Arc<Tera>>,
conn: web::Data<Pool>,
) -> impl Responder {
let connection = conn.get().unwrap();
let article = Article::find_by_url(&connection, &url.into_inner());
pub fn get_article_by_url(url: web::Path<String>, data: web::Data<RubbleData>) -> impl Responder {
let article = Article::find_by_url(&data.postgres(), &url.into_inner());
if let Err(e) = article {
return RubbleResponder::NotFound;
@ -76,11 +64,11 @@ pub fn get_article_by_url(
let view = ArticleView::from(&article1);
let settings = Setting::load(&connection);
let settings = Setting::load(&data.postgres());
let mut context = Context::new();
context.insert("setting", &settings);
context.insert("article", &view);
RubbleResponder::Html(tera.render("archives.html", &context).unwrap())
RubbleResponder::Html(data.render("archives.html", &context))
}

View File

@ -1,3 +1,4 @@
use crate::data::RubbleData;
use crate::models::{article::Article, setting::Setting, CRUD};
use crate::pg_pool::Pool;
use crate::view::article::ArticleView;
@ -6,22 +7,17 @@ use rss::{Channel, ChannelBuilder, Item, ItemBuilder};
use std::collections::HashMap;
#[get("/rss")]
pub fn rss_page(conn: web::Data<Pool>) -> impl Responder {
let connection = conn.get().unwrap();
let articles = Article::read(&connection);
let setting = Setting::load(&connection);
pub fn rss_page(data: web::Data<RubbleData>) -> impl Responder {
let articles = Article::read(&data.postgres());
let setting = Setting::load(&data.postgres());
let items: Vec<Item> = articles
.iter()
.map(ArticleView::from)
.map(|item| {
let url = match item.article.url.clone() {
Some(ref content) if content.len() != 0 => format!("{}/{}", setting.url, content),
_ => format!("{}/archives/{}", setting.url, item.article.id),
};
ItemBuilder::default()
.title(item.article.title.clone())
.link(url)
.link(format!("{}{}", setting.url, item.article.link()))
.description(item.description)
.content(item.markdown_content)
.pub_date(item.article.publish_at.to_string())