initial create user

This commit is contained in:
2021-08-12 15:48:02 +02:00
committed by dietrich
parent b9866a8c19
commit 6837495eba
16 changed files with 650 additions and 288 deletions
-5
View File
@@ -71,8 +71,3 @@ tokio = "0.2.25"
[dev-dependencies.reqwest]
features = ["cookies"]
version = "0.10.10"
[profile]
[profile.release]
lto = true
#codegen-units = 1
+5 -1
View File
@@ -370,7 +370,11 @@ pub async fn webservice(
.service(
web::scope("/json")
.route("/list_links/", web::post().to(views::index_json))
.route("/list_users/", web::post().to(views::index_users_json)),
.route("/list_users/", web::post().to(views::index_users_json))
.route(
"/create_user/",
web::post().to(views::process_create_user_json),
),
)
// login to the admin area
.route("/login/", web::get().to(views::login))
+2 -2
View File
@@ -23,7 +23,7 @@ pub trait UserDbOperations<T> {
}
#[async_trait]
impl UserDbOperations<User> for User {
impl UserDbOperations<Self> for User {
async fn get_user(id: i64, server_config: &ServerConfig) -> Result<Self, ServerError> {
let user = sqlx::query_as!(Self, "Select * from users where id = ? ", id)
.fetch_one(&server_config.db_pool)
@@ -186,7 +186,7 @@ pub trait LinkDbOperations<T> {
}
#[async_trait]
impl LinkDbOperations<Link> for Link {
impl LinkDbOperations<Self> for Link {
async fn get_link_by_code(
code: &str,
server_config: &ServerConfig,
+46 -1
View File
@@ -6,7 +6,7 @@ use shared::{
apirequests::{
general::{Filter, Operation, Ordering},
links::{LinkOverviewColumns, LinkRequestForm},
users::{UserOverviewColumns, UserRequestForm},
users::{UserDelta, UserOverviewColumns, UserRequestForm},
},
datatypes::{Count, FullLink, Link, User},
};
@@ -389,6 +389,51 @@ pub async fn create_user(
}
}
}
/// Create a new user and save it to the database
///
/// # Errors
/// Fails with [`ServerError`] if access to the database fails, this user does not have permissions or the user already exists.
#[instrument(skip(id))]
pub async fn create_user_json(
id: &Identity,
data: &web::Json<UserDelta>,
server_config: &ServerConfig,
) -> Result<Item<User>, ServerError> {
info!("Creating a User: {:?}", &data);
let auth = authenticate(id, server_config).await?;
// Require a password on user creation!
let password = match &data.password {
Some(pass) => pass,
None => {
return Err(ServerError::User(
"A new users does require a password".to_string(),
))
}
};
match auth {
Role::Admin { user } => {
let new_user = NewUser::new(
data.username.clone(),
data.email.clone(),
password,
&server_config.secret,
)?;
new_user.insert_user(server_config).await?;
// querry the new user
let new_user = get_user_by_name(&data.username, server_config).await?;
Ok(Item {
user,
item: new_user,
})
}
Role::Regular { .. } | Role::Disabled | Role::NotAuthenticated => {
Err(ServerError::User("Permission denied!".to_owned()))
}
}
}
/// Take a [`actix_web::web::Form<NewUser>`] and update the corresponding entry in the database.
/// The password is only updated if a new password of at least 4 characters is provided.
/// The `user_id` is never changed.
+20 -1
View File
@@ -14,7 +14,11 @@ use fluent_templates::LanguageIdentifier;
use image::{DynamicImage, ImageOutputFormat, Luma};
use qrcode::{render::svg, QrCode};
use queries::{authenticate, Role};
use shared::apirequests::{links::LinkRequestForm, users::UserRequestForm};
use shared::apirequests::{
general::SuccessMessage,
links::LinkRequestForm,
users::{UserDelta, UserRequestForm},
};
use tera::{Context, Tera};
use tracing::{error, info, instrument, warn};
@@ -346,6 +350,21 @@ pub async fn process_signup(
}
}
#[instrument(skip(id))]
pub async fn process_create_user_json(
config: web::Data<crate::ServerConfig>,
form: web::Json<UserDelta>,
id: Identity,
) -> Result<HttpResponse, ServerError> {
info!("Listing Users to Json api");
match queries::create_user_json(&id, &form, &config).await {
Ok(item) => Ok(HttpResponse::Ok().json2(&SuccessMessage {
message: format!("Successfully saved user: {}", item.item.username),
})),
Err(e) => Err(e),
}
}
#[instrument(skip(id))]
pub async fn toggle_admin(
data: web::Path<String>,
+115 -105
View File
@@ -1,163 +1,173 @@
body {
margin: 0;
padding: 0;
margin: 0;
padding: 0;
}
form {
width: 100%;
width: 100%;
}
.center {
position: absolute;
width: 400px;
height: 400px;
top: 50%;
left: 50%;
margin-left: -200px;
margin-top: -200px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 30px;
color: #333;
position: absolute;
width: 600px;
max-width: 100%;
height: 400px;
max-height: 100%;
top: 50%;
left: 50%;
margin-left: -300px;
margin-top: -200px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 30px;
color: #333;
}
.center input {
width: 100%;
padding: 15px;
margin: 5px;
border-radius: 1px;
border: 1px solid rgb(90, 90, 90);
font-family: inherit;
background-color: #eae9ea;
width: 100%;
padding: 0;
margin: 0;
border-radius: 1px;
border: 1px solid rgb(90, 90, 90);
font-family: inherit;
background-color: #eae9ea;
}
.center {
width: 800px;
height: 600px;
margin-left: -400px;
margin-top: -300px;
.center table p {
font-size: x-small;
margin: 0;
}
table {
border-collapse: collapse;
width: 100%;
border-collapse: collapse;
width: 100%;
}
th, td {
text-align: center;
border: 1px solid #ccc;
padding: 10px;
th,
td {
text-align: center;
border: 1px solid #ccc;
padding: 10px;
}
table tr:nth-child(even) {
background-color: #eee;
background-color: #eee;
}
table tr:nth-child(odd) {
background-color: #fff;
}
background-color: #fff;
}
table tr.filters input {
background-image: url("/static/search.svg");
background-repeat: no-repeat;
background-size: contain;
width: 100%;
padding: 5px;
height: 20px;
text-align: center;
border-radius: 0;
border: none;
background-image: url("/static/search.svg");
background-repeat: no-repeat;
background-size: contain;
width: 100%;
padding: 5px;
height: 20px;
text-align: center;
border-radius: 0;
border: none;
}
table tr.filters td {
padding:5px;
padding: 5px;
}
nav {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-items:stretch;
width:100%;
height: 60px;
}
nav ol {
display:flex;
align-items: center;
list-style-type: none;
margin: 0;
padding: 0;
height: 40px;
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-items: stretch;
width: 100%;
height: 60px;
}
nav li a, nav li div.willkommen {
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
border-radius: 0 0 10px 10px;
nav ol {
display: flex;
align-items: center;
list-style-type: none;
margin: 0;
padding: 0;
height: 40px;
}
nav li a,
nav li div.willkommen {
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
border-radius: 0 0 10px 10px;
}
nav li a {
background: rgb(2,0,36);
background: linear-gradient(180deg, rgba(2,0,36,1) 0%, rgba(9,9,121,1) 35%, rgb(0, 145, 174) 100%);
background: rgb(2, 0, 36);
background: linear-gradient(180deg, rgba(2, 0, 36, 1) 0%, rgba(9, 9, 121, 1) 35%, rgb(0, 145, 174) 100%);
}
nav li {
float: left;
float: left;
}
nav li a:hover {
background: rgb(2,0,36);
background: linear-gradient(180deg, rgba(2,0,36,1) 0%, rgba(9,9,121,1) 35%, rgb(60, 170, 255) 100%);
background: rgb(2, 0, 36);
background: linear-gradient(180deg, rgba(2, 0, 36, 1) 0%, rgba(9, 9, 121, 1) 35%, rgb(60, 170, 255) 100%);
}
nav li {
margin: 5px;
margin: 5px;
}
nav li div{
background-color: burlywood;
text-align: center;
padding: 14px 16px;
border-radius: 0 0 10px 10px;
nav li div {
background-color: burlywood;
text-align: center;
padding: 14px 16px;
border-radius: 0 0 10px 10px;
}
svg {
width: 100px;
height: 100px;
width: 100px;
height: 100px;
}
div.actions {
margin-left:5px;
display: flex;
width:100%;
align-items: center;
padding: 10px;
color: #333;
flex-flow: row wrap;
justify-content: center;
margin-left: 5px;
display: flex;
width: 100%;
align-items: center;
padding: 10px;
color: #333;
flex-flow: row wrap;
justify-content: center;
}
div.danger {
background-color: rgb(235, 127, 77);
font-size: smaller;
border: 2px solid crimson;
background-color: rgb(235, 127, 77);
font-size: smaller;
border: 2px solid crimson;
}
div.danger h3 {
width:100%;
width: 100%;
}
a.button, div.actions input {
width: 250px;
display:block;
padding: 15px;
margin-left: 15px;
text-align: center;
border-radius: 1px;
border: 1px solid rgb(90, 90, 90);
font-family: inherit;
background-color: #eae9ea;
a.button,
div.actions input {
width: 250px;
display: block;
padding: 15px;
margin-left: 15px;
text-align: center;
border-radius: 1px;
border: 1px solid rgb(90, 90, 90);
font-family: inherit;
background-color: #eae9ea;
}
div.editdialog {
background-color: aliceblue;
border: 5px solid rgb(90, 90, 90);
}