split into models and viewmodels
This commit is contained in:
parent
10c50d7ddb
commit
8c106eb9f2
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,7 +1,7 @@
|
|||||||
# Generated by Cargo
|
# Generated by Cargo
|
||||||
# will have compiled files and executables
|
# will have compiled files and executables
|
||||||
/target/
|
/target/
|
||||||
|
**/target/
|
||||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
25
Cargo.toml
25
Cargo.toml
@ -6,22 +6,23 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "4.0.0-beta.12"
|
actix-web = "4.0.1"
|
||||||
actix-rt = "2.5.0"
|
actix-rt = "2.7.0"
|
||||||
actix-session = "0.5.0-beta.4"
|
actix-session = "0.5.0"
|
||||||
tera = "1.15.0"
|
tera = "1.15.0"
|
||||||
|
|
||||||
oauth2 = "4.1"
|
oauth2 = "4.1"
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
|
async-trait = "0.1.53"
|
||||||
rand = "0.8.4"
|
rand = "0.8.5"
|
||||||
url = "2.2.2"
|
url = "2.2.2"
|
||||||
http = "0.2.5"
|
http = "0.2.6"
|
||||||
dotenv = "0.15"
|
dotenv = "0.15"
|
||||||
futures = "0.3.18"
|
futures = "0.3.21"
|
||||||
serde = "1.0.130"
|
serde = "1.0.136"
|
||||||
serde_json = "1.0.71"
|
serde_json = "1.0.79"
|
||||||
serde_derive = "1.0.130"
|
serde_derive = "1.0.136"
|
||||||
|
quote = "1.0"
|
||||||
sea-orm = { version = "0.5.0", features = [ "sqlx-sqlite", "runtime-actix-native-tls", "macros" ], default-features = false }
|
sea-orm = { version = "0.6.0", features = [ "sqlx-sqlite", "runtime-actix-native-tls", "macros" ], default-features = false }
|
||||||
|
|
||||||
|
actix_admin = { path = "actix_admin" }
|
24
actix_admin/Cargo.toml
Normal file
24
actix_admin/Cargo.toml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[package]
|
||||||
|
name = "actix_admin"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
actix-web = "4.0.1"
|
||||||
|
actix-rt = "2.7.0"
|
||||||
|
actix-session = "0.5.0"
|
||||||
|
tera = "1.15.0"
|
||||||
|
actix_admin_macros = { path = "actix_admin_macros" }
|
||||||
|
oauth2 = "4.1"
|
||||||
|
base64 = "0.13.0"
|
||||||
|
async-trait = "0.1.53"
|
||||||
|
rand = "0.8.5"
|
||||||
|
url = "2.2.2"
|
||||||
|
http = "0.2.6"
|
||||||
|
dotenv = "0.15"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
futures = "0.3.21"
|
||||||
|
serde = "1.0.136"
|
||||||
|
serde_json = "1.0.79"
|
||||||
|
serde_derive = "1.0.136"
|
||||||
|
sea-orm = { version = "0.6.0", features = [ "sqlx-sqlite", "runtime-actix-native-tls", "macros" ], default-features = false }
|
30
actix_admin/actix_admin_macros/Cargo.toml
Normal file
30
actix_admin/actix_admin_macros/Cargo.toml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
[package]
|
||||||
|
name = "actix_admin_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
actix-web = "4.0.1"
|
||||||
|
actix-rt = "2.7.0"
|
||||||
|
actix-session = "0.5.0"
|
||||||
|
tera = "1.15.0"
|
||||||
|
|
||||||
|
oauth2 = "4.1"
|
||||||
|
base64 = "0.13.0"
|
||||||
|
|
||||||
|
quote = "1.0"
|
||||||
|
syn = { version = "1.0", features = ["full", "extra-traits"] }
|
||||||
|
proc-macro2 = { version = "1.0.36", default-features = false }
|
||||||
|
|
||||||
|
rand = "0.8.5"
|
||||||
|
url = "2.2.2"
|
||||||
|
http = "0.2.6"
|
||||||
|
dotenv = "0.15"
|
||||||
|
futures = "0.3.21"
|
||||||
|
serde = "1.0.136"
|
||||||
|
serde_json = "1.0.79"
|
||||||
|
serde_derive = "1.0.136"
|
||||||
|
sea-orm = { version = "0.6.0", features = [ "sqlx-sqlite", "runtime-actix-native-tls", "macros" ], default-features = false }
|
40
actix_admin/actix_admin_macros/src/lib.rs
Normal file
40
actix_admin/actix_admin_macros/src/lib.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use proc_macro;
|
||||||
|
use quote::quote;
|
||||||
|
|
||||||
|
#[proc_macro_derive(DeriveActixAdminModel)]
|
||||||
|
pub fn derive_crud_fns(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
let expanded = quote! {
|
||||||
|
use std::convert::From;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use actix_admin::{ ActixAdminModelTrait, ActixAdminModel };
|
||||||
|
|
||||||
|
impl From<Entity> for ActixAdminModel {
|
||||||
|
fn from(entity: Entity) -> Self {
|
||||||
|
ActixAdminModel {
|
||||||
|
fields: Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[async_trait]
|
||||||
|
impl ActixAdminModelTrait for Entity {
|
||||||
|
async fn list(db: &DatabaseConnection, page: usize, posts_per_page: usize) -> Vec<ActixAdminModel> {
|
||||||
|
use sea_orm::{ query::* };
|
||||||
|
let paginator = Entity::find()
|
||||||
|
.order_by_asc(Column::Id)
|
||||||
|
.paginate(db, posts_per_page);
|
||||||
|
let entities = paginator
|
||||||
|
.fetch_page(page - 1)
|
||||||
|
.await
|
||||||
|
.expect("could not retrieve entities");
|
||||||
|
//entities to ActixAdminModel
|
||||||
|
vec![
|
||||||
|
ActixAdminModel {
|
||||||
|
fields: Vec::new()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
proc_macro::TokenStream::from(expanded)
|
||||||
|
}
|
24
actix_admin/actix_admin_macros/tests/macros_sqlx.rs
Normal file
24
actix_admin/actix_admin_macros/tests/macros_sqlx.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use actix_admin_macros::ActixAdmin;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, ActixAdmin)]
|
||||||
|
#[sea_orm(table_name = "test")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
pub id: i32,
|
||||||
|
pub title: String,
|
||||||
|
#[sea_orm(column_type = "Text")]
|
||||||
|
pub text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_macro() {
|
||||||
|
assert_eq!(4, 2);
|
||||||
|
}
|
153
actix_admin/src/lib.rs
Normal file
153
actix_admin/src/lib.rs
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
use actix_web::{error, guard, web, Error, HttpRequest, HttpResponse};
|
||||||
|
use actix_web::{ dev, App, FromRequest};
|
||||||
|
use actix_web::error::ErrorBadRequest;
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use tera::{Context, Tera};
|
||||||
|
use futures::future::{ok, err, Ready};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use sea_orm::DatabaseConnection;
|
||||||
|
use sea_orm::EntityTrait;
|
||||||
|
use sea_orm::ModelTrait;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
pub use actix_admin_macros::DeriveActixAdminModel;
|
||||||
|
|
||||||
|
const DEFAULT_POSTS_PER_PAGE: usize = 5;
|
||||||
|
|
||||||
|
// templates
|
||||||
|
lazy_static! {
|
||||||
|
static ref TERA: Tera = Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paging
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct Params {
|
||||||
|
page: Option<usize>,
|
||||||
|
posts_per_page: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Field {
|
||||||
|
Text
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppDataTrait
|
||||||
|
pub trait AppDataTrait {
|
||||||
|
fn get_db(&self) -> &DatabaseConnection;
|
||||||
|
fn get_view_model_map(&self) -> &HashMap<&'static str, ActixAdminViewModel>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActixAdminModel
|
||||||
|
#[async_trait]
|
||||||
|
pub trait ActixAdminModelTrait {
|
||||||
|
async fn list(db: &DatabaseConnection, page: usize, posts_per_page: usize) -> Vec<ActixAdminModel>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ActixAdminModel {
|
||||||
|
pub fields: Vec<(&'static str, Field)>
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActixAdminViewModel
|
||||||
|
pub trait ActixAdminViewModelTrait : Clone {
|
||||||
|
fn get_model_name(&self) -> &str;
|
||||||
|
//fn get_entities() -> Vec<ActixAdminModel>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActixAdminViewModelTrait for ActixAdminViewModel {
|
||||||
|
fn get_model_name(&self) -> &str {
|
||||||
|
&self.entity_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ActixAdminViewModel {
|
||||||
|
pub entity_name: &'static str,
|
||||||
|
pub admin_model: ActixAdminModel
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActixAdminController
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ActixAdmin {
|
||||||
|
view_models: HashMap<&'static str, ActixAdminViewModel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActixAdmin {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let actix_admin = ActixAdmin {
|
||||||
|
view_models: HashMap::new(),
|
||||||
|
};
|
||||||
|
actix_admin
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_scope<T: AppDataTrait + 'static>(self, _app_state: &T) -> actix_web::Scope {
|
||||||
|
let mut scope = web::scope("/admin").route("/", web::get().to(index::<T>));
|
||||||
|
|
||||||
|
for view_model in self.view_models {
|
||||||
|
scope = scope.service(
|
||||||
|
web::scope(&format!("/{}", view_model.0)).route("/list", web::get().to(list::<T>))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
scope
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_entity(mut self, view_model: ActixAdminViewModel) -> Self {
|
||||||
|
self.view_models.insert(view_model.entity_name, view_model);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_view_model_map(&self) -> HashMap<&'static str, ActixAdminViewModel> {
|
||||||
|
self.view_models.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn index<T: AppDataTrait>(data: web::Data<T>) -> Result<HttpResponse, Error> {
|
||||||
|
let keys = Vec::from_iter(data.get_view_model_map().keys());
|
||||||
|
|
||||||
|
let mut ctx = Context::new();
|
||||||
|
ctx.insert("view_models", &keys);
|
||||||
|
|
||||||
|
let body = TERA
|
||||||
|
.render("index.html", &ctx)
|
||||||
|
.map_err(|_| error::ErrorInternalServerError("Template error"))?;
|
||||||
|
Ok(HttpResponse::Ok().content_type("text/html").body(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn list<T: AppDataTrait>(req: HttpRequest, data: web::Data<T>) -> Result<HttpResponse, Error> {
|
||||||
|
let db = &data.get_db();
|
||||||
|
let params = web::Query::<Params>::from_query(req.query_string()).unwrap();
|
||||||
|
|
||||||
|
let page = params.page.unwrap_or(1);
|
||||||
|
let posts_per_page = params.posts_per_page.unwrap_or(DEFAULT_POSTS_PER_PAGE);
|
||||||
|
|
||||||
|
let columns: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
// let paginator = post::Entity::find()
|
||||||
|
// .order_by_asc(post::Column::Id)
|
||||||
|
// .paginate(db, posts_per_page);
|
||||||
|
//let num_pages = paginator.num_pages().await.ok().unwrap();
|
||||||
|
|
||||||
|
let posts: Vec<&str> = Vec::new();
|
||||||
|
//let posts = paginator
|
||||||
|
// .fetch_page(page - 1)
|
||||||
|
// .await
|
||||||
|
// .expect("could not retrieve posts");
|
||||||
|
let mut ctx = Context::new();
|
||||||
|
ctx.insert("posts", &posts);
|
||||||
|
ctx.insert("page", &page);
|
||||||
|
ctx.insert("posts_per_page", &posts_per_page);
|
||||||
|
ctx.insert("num_pages", "5" /*&num_pages*/);
|
||||||
|
ctx.insert("columns", &columns);
|
||||||
|
|
||||||
|
// let body = data.tmpl
|
||||||
|
// .render("list.html", &ctx)
|
||||||
|
// .map_err(|_| error::ErrorInternalServerError("Template error"))?;
|
||||||
|
//Ok(HttpResponse::Ok().content_type("text/html").body(body))
|
||||||
|
Ok(HttpResponse::Ok()
|
||||||
|
.content_type("text/html")
|
||||||
|
.body("<html></html>"))
|
||||||
|
}
|
14
actix_admin/templates/base.html
Normal file
14
actix_admin/templates/base.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Actix Admin</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block content %}
|
||||||
|
{% endblock content %}
|
||||||
|
</body>
|
||||||
|
</html>
|
5
actix_admin/templates/index.html
Normal file
5
actix_admin/templates/index.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<p>Index</p>
|
||||||
|
{% endblock content %}
|
9
actix_admin/templates/list.html
Normal file
9
actix_admin/templates/list.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
Hello
|
||||||
|
<p>posts: {{ posts }}</p>
|
||||||
|
<p>page: {{ page }}</p>
|
||||||
|
<p>posts_per_page: {{ posts_per_page }}</p>
|
||||||
|
<p>num_pages: {{ num_pages }}</p>
|
||||||
|
{% endblock content %}
|
@ -1,65 +0,0 @@
|
|||||||
use actix_web::{web, guard, HttpRequest, HttpResponse, Error, error};
|
|
||||||
use tera::{ Tera, Context};
|
|
||||||
|
|
||||||
use crate::entity::Post;
|
|
||||||
use crate::entity::post;
|
|
||||||
|
|
||||||
use sea_orm::{ entity::*, query::*, SelectorTrait, ModelTrait, ConnectionTrait, ColumnTrait, PaginatorTrait, EntityTrait };
|
|
||||||
use sea_orm::{{ DatabaseConnection, ConnectOptions }};
|
|
||||||
|
|
||||||
const DEFAULT_POSTS_PER_PAGE: usize = 5;
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct Params {
|
|
||||||
page: Option<usize>,
|
|
||||||
posts_per_page: Option<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn index(data: web::Data<super::AppState>) -> &'static str {
|
|
||||||
"Welcome!"
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn list<T: EntityTrait>(
|
|
||||||
req: HttpRequest,
|
|
||||||
data: web::Data<super::AppState>) -> Result<HttpResponse, Error>
|
|
||||||
{
|
|
||||||
let db = &data.db;
|
|
||||||
let params = web::Query::<Params>::from_query(req.query_string()).unwrap();
|
|
||||||
|
|
||||||
let page = params.page.unwrap_or(1);
|
|
||||||
let posts_per_page = params.posts_per_page.unwrap_or(DEFAULT_POSTS_PER_PAGE);
|
|
||||||
let paginator = Post::find()
|
|
||||||
.order_by_asc(post::Column::Id)
|
|
||||||
.paginate(db, posts_per_page);
|
|
||||||
let num_pages = paginator.num_pages().await.ok().unwrap();
|
|
||||||
|
|
||||||
let posts = paginator
|
|
||||||
.fetch_page(page - 1)
|
|
||||||
.await
|
|
||||||
.expect("could not retrieve posts");
|
|
||||||
|
|
||||||
let mut ctx = Context::new();
|
|
||||||
ctx.insert("posts", &posts);
|
|
||||||
ctx.insert("page", &page);
|
|
||||||
ctx.insert("posts_per_page", &posts_per_page);
|
|
||||||
ctx.insert("num_pages", &num_pages);
|
|
||||||
|
|
||||||
let body = data.tmpl
|
|
||||||
.render("list.html", &ctx)
|
|
||||||
.map_err(|_| error::ErrorInternalServerError("Template error"))?;
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn entity_scope<T: EntityTrait>(entity: T) -> actix_web::Scope {
|
|
||||||
let entity_name = entity.table_name();
|
|
||||||
let scope = web::scope(&format!("/{}",entity_name))
|
|
||||||
.route("/list", web::get().to(list::<T>));
|
|
||||||
scope
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn admin_scope() -> actix_web::Scope {
|
|
||||||
let scope = web::scope("/admin")
|
|
||||||
.route("/", web::get().to(index))
|
|
||||||
.service(entity_scope(Post));
|
|
||||||
scope
|
|
||||||
}
|
|
@ -1,7 +1,9 @@
|
|||||||
// setup
|
// setup
|
||||||
use sea_orm::sea_query::{ColumnDef, TableCreateStatement};
|
use sea_orm::sea_query::{ColumnDef, TableCreateStatement};
|
||||||
use sea_orm::{error::*, sea_query, ConnectionTrait, DbConn, ExecResult};
|
use sea_orm::{error::*, sea_query, ConnectionTrait, DbConn, ExecResult};
|
||||||
|
use sea_orm::{{ DatabaseConnection, ConnectOptions }};
|
||||||
|
use sea_orm::{ entity::*, query::*, SelectorTrait, ModelTrait, ColumnTrait, PaginatorTrait, EntityTrait };
|
||||||
|
use async_trait::async_trait;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
pub use post::Entity as Post;
|
pub use post::Entity as Post;
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
|
use actix_admin::{ DeriveActixAdminModel };
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, DeriveActixAdminModel)]
|
||||||
#[sea_orm(table_name = "post")]
|
#[sea_orm(table_name = "post")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
|
35
src/main.rs
35
src/main.rs
@ -11,21 +11,35 @@ use oauth2::{
|
|||||||
};
|
};
|
||||||
use std::time::{Duration};
|
use std::time::{Duration};
|
||||||
use std::env;
|
use std::env;
|
||||||
use sea_orm::{{ DatabaseConnection, ConnectOptions }};
|
use sea_orm::{{ DatabaseConnection, ConnectOptions, EntityName }};
|
||||||
|
use actix_admin::{ActixAdminViewModelTrait, AppDataTrait, ActixAdminViewModel, ActixAdminModel};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
mod web_auth;
|
mod web_auth;
|
||||||
mod entity;
|
mod entity;
|
||||||
mod actix_admin;
|
|
||||||
|
use entity::{ Post };
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub oauth: BasicClient,
|
pub oauth: BasicClient,
|
||||||
pub api_base_url: String,
|
pub api_base_url: String,
|
||||||
pub tmpl: Tera,
|
pub tmpl: Tera,
|
||||||
pub db: DatabaseConnection
|
pub db: DatabaseConnection,
|
||||||
|
pub view_model_map: HashMap<&'static str, ActixAdminViewModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index(session: Session, data: web::Data<AppState>) -> HttpResponse {
|
impl AppDataTrait for AppState {
|
||||||
|
fn get_db(&self) -> &DatabaseConnection {
|
||||||
|
&self.db
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_view_model_map(&self) -> &HashMap<&'static str, ActixAdminViewModel> {
|
||||||
|
&self.view_model_map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn index(session: Session, data: web::Data<AppState>) -> HttpResponse {
|
||||||
let login = session.get::<web_auth::UserInfo>("user_info").unwrap();
|
let login = session.get::<web_auth::UserInfo>("user_info").unwrap();
|
||||||
let web_auth_link = if login.is_some() { "logout" } else { "login" };
|
let web_auth_link = if login.is_some() { "logout" } else { "login" };
|
||||||
|
|
||||||
@ -85,18 +99,27 @@ async fn main() {
|
|||||||
let conn = sea_orm::Database::connect(opt).await.unwrap();
|
let conn = sea_orm::Database::connect(opt).await.unwrap();
|
||||||
let _ = entity::create_post_table(&conn).await;
|
let _ = entity::create_post_table(&conn).await;
|
||||||
|
|
||||||
|
let viewmodel_entity = ActixAdminViewModel {
|
||||||
|
entity_name: "posts",
|
||||||
|
admin_model: ActixAdminModel::from(Post)
|
||||||
|
};
|
||||||
|
|
||||||
|
let actix_admin = actix_admin::ActixAdmin::new()
|
||||||
|
.add_entity(viewmodel_entity.clone());
|
||||||
|
|
||||||
let app_state = AppState {
|
let app_state = AppState {
|
||||||
oauth: client,
|
oauth: client,
|
||||||
api_base_url,
|
api_base_url,
|
||||||
tmpl: tera,
|
tmpl: tera,
|
||||||
db: conn
|
db: conn,
|
||||||
|
view_model_map: actix_admin.get_view_model_map()
|
||||||
};
|
};
|
||||||
|
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
.app_data(web::Data::new(app_state.clone()))
|
.app_data(web::Data::new(app_state.clone()))
|
||||||
.wrap(CookieSession::signed(&[0; 32]).secure(false))
|
.wrap(CookieSession::signed(&[0; 32]).secure(false))
|
||||||
.service(actix_admin::admin_scope())
|
.service(actix_admin.clone().create_scope(&app_state))
|
||||||
.route("/", web::get().to(index))
|
.route("/", web::get().to(index))
|
||||||
.route("/login", web::get().to(web_auth::login))
|
.route("/login", web::get().to(web_auth::login))
|
||||||
.route("/logout", web::get().to(web_auth::logout))
|
.route("/logout", web::get().to(web_auth::logout))
|
||||||
|
@ -10,7 +10,7 @@ use oauth2::{
|
|||||||
use std::str;
|
use std::str;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub fn login(data: web::Data<super::AppState>) -> HttpResponse {
|
pub async fn login(data: web::Data<super::AppState>) -> HttpResponse {
|
||||||
// Create a PKCE code verifier and SHA-256 encode it as a code challenge.
|
// Create a PKCE code verifier and SHA-256 encode it as a code challenge.
|
||||||
// let (_pkce_code_challenge, _pkce_code_verifier) = PkceCodeChallenge::new_random_sha256();
|
// let (_pkce_code_challenge, _pkce_code_verifier) = PkceCodeChallenge::new_random_sha256();
|
||||||
// Generate the authorization URL to which we'll redirect the user.
|
// Generate the authorization URL to which we'll redirect the user.
|
||||||
@ -28,7 +28,7 @@ pub fn login(data: web::Data<super::AppState>) -> HttpResponse {
|
|||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn logout(session: Session) -> HttpResponse {
|
pub async fn logout(session: Session) -> HttpResponse {
|
||||||
session.remove("user_info");
|
session.remove("user_info");
|
||||||
HttpResponse::Found()
|
HttpResponse::Found()
|
||||||
.append_header((header::LOCATION, "/".to_string()))
|
.append_header((header::LOCATION, "/".to_string()))
|
||||||
|
Loading…
Reference in New Issue
Block a user