Reformat
This commit is contained in:
parent
c848037dcb
commit
3bf0f8de74
20 changed files with 117 additions and 139 deletions
|
@ -2,8 +2,8 @@ use anyhow::Result;
|
|||
use clap::{Parser, Subcommand};
|
||||
use pique::db::establish_connection;
|
||||
use pique::models::users::{self, NewUser};
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::{distributions::DistString, thread_rng};
|
||||
use rand::distributions::{Alphanumeric, DistString};
|
||||
use rand::thread_rng;
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() -> Result<()> {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use pique::server;
|
||||
|
||||
#[tokio::main]
|
||||
|
|
58
src/db.rs
58
src/db.rs
|
@ -1,11 +1,8 @@
|
|||
use diesel::prelude::*;
|
||||
use diesel::r2d2::ConnectionManager;
|
||||
use diesel::r2d2::Pool;
|
||||
use diesel::r2d2::{ConnectionManager, Pool};
|
||||
use diesel::SqliteConnection;
|
||||
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
|
||||
|
||||
use crate::{password, prelude::*};
|
||||
|
||||
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!();
|
||||
|
||||
/// Establishes a connection to the database using the given URL.
|
||||
|
@ -14,7 +11,8 @@ pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!();
|
|||
/// * `url` - The database URL to connect to.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if the database URL is not set or if the connection cannot be established.
|
||||
/// Panics if the database URL is not set or if the connection cannot be
|
||||
/// established.
|
||||
pub fn establish_connection(url: &str) -> SqliteConnection {
|
||||
SqliteConnection::establish(url).unwrap_or_else(|_| panic!("Error connecting to {}", url))
|
||||
}
|
||||
|
@ -45,53 +43,3 @@ pub fn build_connection_pool(url: &str) -> Pool<ConnectionManager<SqliteConnecti
|
|||
pub fn migrate(conn: &mut SqliteConnection) {
|
||||
conn.run_pending_migrations(MIGRATIONS).unwrap();
|
||||
}
|
||||
|
||||
pub struct NewUser {
|
||||
pub full_name: String,
|
||||
pub email: String,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
impl NewUser {
|
||||
pub fn validate(&self) -> Result<(), Vec<ValidationError>> {
|
||||
let mut validation_errors = vec![];
|
||||
|
||||
if self.full_name.len() > 100 {
|
||||
validation_errors.push(ValidationError::on("full_name", "too long (max=100)"));
|
||||
}
|
||||
|
||||
if self.email.len() > 100 {
|
||||
validation_errors.push(ValidationError::on("email", "too long (max=100)"));
|
||||
}
|
||||
|
||||
if self.username.len() > 100 {
|
||||
validation_errors.push(ValidationError::on("username", "too long (max=32)"));
|
||||
}
|
||||
|
||||
if validation_errors.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(validation_errors)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hash_password(&self) -> String {
|
||||
password::hash(&self.password)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ValidationError {
|
||||
pub field: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl ValidationError {
|
||||
pub fn on(field: &str, message: &str) -> ValidationError {
|
||||
ValidationError {
|
||||
field: field.to_owned(),
|
||||
message: message.to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ pub mod projects;
|
|||
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::Response;
|
||||
pub use login::login_page;
|
||||
pub use login::login_submit;
|
||||
pub use login::{login_page, login_submit};
|
||||
use tracing::error;
|
||||
|
||||
pub fn internal_server_error() -> Response {
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
use axum::{extract::Path, http::StatusCode, response::Redirect, Form};
|
||||
use axum::extract::Path;
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::Redirect;
|
||||
use axum::Form;
|
||||
use axum_login::AuthSession;
|
||||
|
||||
use crate::{
|
||||
handler::internal_error,
|
||||
models::{
|
||||
documents::{self, NewDocument},
|
||||
users::User,
|
||||
},
|
||||
permissions::{self, query::Permission},
|
||||
prelude::*,
|
||||
};
|
||||
use crate::handler::internal_error;
|
||||
use crate::models::documents::{self, NewDocument};
|
||||
use crate::models::users::User;
|
||||
use crate::permissions::query::Permission;
|
||||
use crate::permissions::{self};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub async fn documents_page(
|
||||
State(provider): State<Provider>,
|
||||
|
|
|
@ -2,8 +2,8 @@ use axum::response::Redirect;
|
|||
use axum_login::AuthSession;
|
||||
|
||||
use crate::models::projects::Project;
|
||||
|
||||
use {crate::permissions, crate::prelude::*};
|
||||
use crate::permissions;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub async fn home_page(
|
||||
State(provider): State<Provider>,
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use axum::{response::Redirect, Form};
|
||||
use axum::response::Redirect;
|
||||
use axum::Form;
|
||||
use axum_login::AuthSession;
|
||||
|
||||
use crate::{handler::internal_server_error, prelude::*, session::Credentials};
|
||||
use crate::handler::internal_server_error;
|
||||
use crate::prelude::*;
|
||||
use crate::session::Credentials;
|
||||
|
||||
pub struct LoginTemplate {
|
||||
pub username: String,
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
use axum::{http::StatusCode, response::Redirect, Form};
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::Redirect;
|
||||
use axum::Form;
|
||||
use axum_login::AuthSession;
|
||||
|
||||
use crate::{
|
||||
handler::internal_server_error,
|
||||
models::{
|
||||
project_memberships::{self, ProjectRole},
|
||||
projects::{self, NewProject},
|
||||
users::User,
|
||||
},
|
||||
permissions,
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use super::internal_error;
|
||||
use crate::handler::internal_server_error;
|
||||
use crate::models::project_memberships::{self, ProjectRole};
|
||||
use crate::models::projects::{self, NewProject};
|
||||
use crate::models::users::User;
|
||||
use crate::permissions;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub async fn projects_page(
|
||||
State(provider): State<Provider>,
|
||||
|
|
|
@ -12,3 +12,4 @@ pub mod serialize;
|
|||
pub mod server;
|
||||
pub mod session;
|
||||
pub mod templates;
|
||||
pub mod validation;
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use diesel::prelude::*;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::schema::documents::dsl;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::DbError;
|
||||
use crate::schema::documents::dsl;
|
||||
|
||||
#[derive(Queryable, Selectable, Debug, Clone, Serialize)]
|
||||
#[diesel(table_name = crate::schema::documents)]
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use diesel::{expression::AsExpression, prelude::*, sql_types::Text};
|
||||
use std::fmt;
|
||||
|
||||
use diesel::expression::AsExpression;
|
||||
use diesel::prelude::*;
|
||||
use diesel::sql_types::Text;
|
||||
|
||||
#[derive(AsExpression, Debug, Clone)]
|
||||
#[diesel(sql_type = Text)]
|
||||
pub enum ProjectRole {
|
||||
|
@ -63,9 +66,10 @@ pub struct NewProjectMembership {
|
|||
}
|
||||
|
||||
pub mod query {
|
||||
use super::*;
|
||||
use diesel::SqliteConnection;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub fn create(
|
||||
db: &mut SqliteConnection,
|
||||
user_id: &str,
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use diesel::prelude::*;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::schema::projects::dsl;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::DbError;
|
||||
use crate::schema::projects::dsl;
|
||||
|
||||
#[derive(Queryable, Selectable, Debug, Clone, Serialize)]
|
||||
#[diesel(table_name = crate::schema::projects)]
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use diesel::prelude::*;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::schema::users::dsl;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::password;
|
||||
|
||||
use super::DbError;
|
||||
use crate::db::ValidationError;
|
||||
use crate::password;
|
||||
use crate::schema::users::dsl;
|
||||
|
||||
#[derive(Queryable, Selectable, Debug, Clone, Serialize)]
|
||||
#[diesel(table_name = crate::schema::users)]
|
||||
|
@ -40,6 +39,28 @@ impl NewUser {
|
|||
password_hash,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> Result<(), Vec<ValidationError>> {
|
||||
let mut validation_errors = vec![];
|
||||
|
||||
if self.name.len() > 100 {
|
||||
validation_errors.push(ValidationError::on("name", "too long (max=100)"));
|
||||
}
|
||||
|
||||
if self.email.len() > 100 {
|
||||
validation_errors.push(ValidationError::on("email", "too long (max=100)"));
|
||||
}
|
||||
|
||||
if self.username.len() > 32 {
|
||||
validation_errors.push(ValidationError::on("username", "too long (max=32)"));
|
||||
}
|
||||
|
||||
if validation_errors.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(validation_errors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Query<'a> {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
pub mod query {
|
||||
use diesel::prelude::*;
|
||||
use diesel::SqliteConnection;
|
||||
|
||||
use crate::models::documents::Document;
|
||||
use crate::models::project_memberships::ProjectRole;
|
||||
use crate::models::projects::Project;
|
||||
use diesel::prelude::*;
|
||||
use diesel::SqliteConnection;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Permission {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
pub use crate::provider::Provider;
|
||||
pub use axum::extract::State;
|
||||
pub use axum::response::{Html, IntoResponse, Response};
|
||||
pub use minijinja::context;
|
||||
pub use serde::{Deserialize, Serialize};
|
||||
pub use tracing::{debug, error, info, warn};
|
||||
pub use uuid::Uuid;
|
||||
|
||||
pub use crate::provider::Provider;
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use diesel::{
|
||||
r2d2::{ConnectionManager, Pool},
|
||||
SqliteConnection,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
use diesel::r2d2::{ConnectionManager, Pool};
|
||||
use diesel::SqliteConnection;
|
||||
use minijinja_autoreload::AutoReloader;
|
||||
use thiserror::Error;
|
||||
|
||||
use minijinja_autoreload::AutoReloader;
|
||||
|
||||
use crate::{handler::internal_server_error, prelude::*};
|
||||
use crate::handler::internal_server_error;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub type ConnectionPool = Pool<ConnectionManager<SqliteConnection>>;
|
||||
pub type PooledConnection = diesel::r2d2::PooledConnection<ConnectionManager<SqliteConnection>>;
|
||||
|
@ -38,7 +37,8 @@ impl Provider {
|
|||
}
|
||||
|
||||
pub fn render<T: Serialize>(&self, path: &str, data: T) -> anyhow::Result<String> {
|
||||
// TODO: more graceful handling of the potential errors here; this should not use anyhow
|
||||
// TODO: more graceful handling of the potential errors here; this should not
|
||||
// use anyhow
|
||||
let env = self.template_loader.acquire_env().unwrap();
|
||||
let template = env.get_template(path)?;
|
||||
let rendered = template.render(data)?;
|
||||
|
|
|
@ -1,38 +1,31 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use axum::{
|
||||
routing::{get, post},
|
||||
Router,
|
||||
};
|
||||
use axum::routing::{get, post};
|
||||
use axum::Router;
|
||||
use axum_login::AuthManagerLayerBuilder;
|
||||
use clap::Parser;
|
||||
use diesel_migrations::{embed_migrations, EmbeddedMigrations};
|
||||
use tower_http::{
|
||||
services::ServeDir,
|
||||
trace::{DefaultOnRequest, DefaultOnResponse, TraceLayer},
|
||||
};
|
||||
use tower_http::services::ServeDir;
|
||||
use tower_http::trace::{DefaultOnRequest, DefaultOnResponse, TraceLayer};
|
||||
use tower_sessions::SessionManagerLayer;
|
||||
use tower_sessions_sqlx_store::{sqlx::SqlitePool, SqliteStore};
|
||||
use tower_sessions_sqlx_store::sqlx::SqlitePool;
|
||||
use tower_sessions_sqlx_store::SqliteStore;
|
||||
use tracing::Level;
|
||||
|
||||
use crate::{
|
||||
config::CommandLineOptions,
|
||||
provider::Provider,
|
||||
db,
|
||||
handler::{
|
||||
documents::{
|
||||
create_document_page, create_document_submit, documents_page, edit_document_page,
|
||||
edit_document_submit,
|
||||
},
|
||||
home::home_page,
|
||||
login::logout,
|
||||
login_page, login_submit,
|
||||
projects::{create_project_page, create_project_submit, projects_page},
|
||||
},
|
||||
logging::setup_logging,
|
||||
templates::make_template_loader,
|
||||
use crate::config::CommandLineOptions;
|
||||
use crate::db;
|
||||
use crate::handler::documents::{
|
||||
create_document_page, create_document_submit, documents_page, edit_document_page,
|
||||
edit_document_submit,
|
||||
};
|
||||
use crate::handler::home::home_page;
|
||||
use crate::handler::login::logout;
|
||||
use crate::handler::projects::{create_project_page, create_project_submit, projects_page};
|
||||
use crate::handler::{login_page, login_submit};
|
||||
use crate::logging::setup_logging;
|
||||
use crate::provider::Provider;
|
||||
use crate::templates::make_template_loader;
|
||||
|
||||
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations/");
|
||||
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use async_trait::async_trait;
|
||||
use axum_login::{AuthUser, AuthnBackend, UserId};
|
||||
|
||||
use crate::{
|
||||
models::{self, users, DbError},
|
||||
password,
|
||||
prelude::*,
|
||||
};
|
||||
use crate::models::{self, users, DbError};
|
||||
use crate::password;
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Credentials {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use free_icons::IconAttrs;
|
||||
use minijinja::{path_loader, Environment};
|
||||
use minijinja::{Error, ErrorKind};
|
||||
use minijinja::{path_loader, Environment, Error, ErrorKind};
|
||||
use minijinja_autoreload::AutoReloader;
|
||||
|
||||
pub fn make_template_loader(auto_reload: bool) -> AutoReloader {
|
||||
|
|
16
src/validation.rs
Normal file
16
src/validation.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ValidationError {
|
||||
pub field: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl ValidationError {
|
||||
pub fn on(field: &str, message: &str) -> ValidationError {
|
||||
ValidationError {
|
||||
field: field.to_owned(),
|
||||
message: message.to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue