Merge pull request 'add family' (#167) from family into staging
Reviewed-on: #167
This commit is contained in:
commit
85124cd699
@ -15,7 +15,12 @@ CREATE TABLE IF NOT EXISTS "user" (
|
|||||||
"nickname" text,
|
"nickname" text,
|
||||||
"notes" text,
|
"notes" text,
|
||||||
"phone" text,
|
"phone" text,
|
||||||
"address" text
|
"address" text,
|
||||||
|
"family_id" INTEGER REFERENCES family(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "family" (
|
||||||
|
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS "role" (
|
CREATE TABLE IF NOT EXISTS "role" (
|
||||||
|
55
src/model/family.rs
Normal file
55
src/model/family.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use serde::Serialize;
|
||||||
|
use sqlx::{sqlite::SqliteQueryResult, FromRow, SqlitePool};
|
||||||
|
|
||||||
|
#[derive(FromRow, Serialize, Clone)]
|
||||||
|
pub struct Family {
|
||||||
|
id: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Clone)]
|
||||||
|
pub struct FamilyWithMembers {
|
||||||
|
id: i64,
|
||||||
|
names: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Family {
|
||||||
|
pub async fn all(db: &SqlitePool) -> Vec<Self> {
|
||||||
|
sqlx::query_as!(Self, "SELECT id FROM role")
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn new(db: &SqlitePool) -> i64 {
|
||||||
|
let result: SqliteQueryResult = sqlx::query("INSERT INTO family DEFAULT VALUES")
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
result.last_insert_rowid()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn all_with_members(db: &SqlitePool) -> Vec<FamilyWithMembers> {
|
||||||
|
sqlx::query_as!(
|
||||||
|
FamilyWithMembers,
|
||||||
|
"
|
||||||
|
SELECT
|
||||||
|
family.id as id,
|
||||||
|
GROUP_CONCAT(user.name, ', ') as names
|
||||||
|
FROM family
|
||||||
|
LEFT JOIN
|
||||||
|
user ON family.id = user.family_id
|
||||||
|
GROUP BY family.id;"
|
||||||
|
)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn find_by_id(db: &SqlitePool, id: i32) -> Option<Self> {
|
||||||
|
sqlx::query_as!(Self, "SELECT id FROM family WHERE id like ?", id)
|
||||||
|
.fetch_one(db)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ use self::{
|
|||||||
|
|
||||||
pub mod boat;
|
pub mod boat;
|
||||||
pub mod boatdamage;
|
pub mod boatdamage;
|
||||||
|
pub mod family;
|
||||||
pub mod location;
|
pub mod location;
|
||||||
pub mod log;
|
pub mod log;
|
||||||
pub mod logbook;
|
pub mod logbook;
|
||||||
|
@ -16,7 +16,7 @@ impl Rower {
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
User,
|
User,
|
||||||
"
|
"
|
||||||
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address
|
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address, family_id
|
||||||
FROM user
|
FROM user
|
||||||
WHERE id in (SELECT rower_id FROM rower WHERE logbook_id=?)
|
WHERE id in (SELECT rower_id FROM rower WHERE logbook_id=?)
|
||||||
",
|
",
|
||||||
|
@ -13,7 +13,7 @@ use rocket::{
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||||
|
|
||||||
use super::{log::Log, tripdetails::TripDetails, Day};
|
use super::{family::Family, log::Log, tripdetails::TripDetails, Day};
|
||||||
use crate::tera::admin::user::UserEditForm;
|
use crate::tera::admin::user::UserEditForm;
|
||||||
|
|
||||||
#[derive(FromRow, Debug, Serialize, Deserialize)]
|
#[derive(FromRow, Debug, Serialize, Deserialize)]
|
||||||
@ -33,6 +33,7 @@ pub struct User {
|
|||||||
pub notes: Option<String>,
|
pub notes: Option<String>,
|
||||||
pub phone: Option<String>,
|
pub phone: Option<String>,
|
||||||
pub address: Option<String>,
|
pub address: Option<String>,
|
||||||
|
pub family_id: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@ -161,7 +162,7 @@ impl User {
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address
|
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address, family_id
|
||||||
FROM user
|
FROM user
|
||||||
WHERE id like ?
|
WHERE id like ?
|
||||||
",
|
",
|
||||||
@ -176,7 +177,7 @@ WHERE id like ?
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address
|
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address, family_id
|
||||||
FROM user
|
FROM user
|
||||||
WHERE id like ?
|
WHERE id like ?
|
||||||
",
|
",
|
||||||
@ -191,7 +192,7 @@ WHERE id like ?
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address
|
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address, family_id
|
||||||
FROM user
|
FROM user
|
||||||
WHERE name like ?
|
WHERE name like ?
|
||||||
",
|
",
|
||||||
@ -233,7 +234,7 @@ WHERE name like ?
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address
|
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address, family_id
|
||||||
FROM user
|
FROM user
|
||||||
WHERE deleted = 0
|
WHERE deleted = 0
|
||||||
ORDER BY last_access DESC
|
ORDER BY last_access DESC
|
||||||
@ -248,7 +249,7 @@ ORDER BY last_access DESC
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address
|
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address, family_id
|
||||||
FROM user
|
FROM user
|
||||||
WHERE deleted = 0 AND dob != '' and weight != '' and sex != ''
|
WHERE deleted = 0 AND dob != '' and weight != '' and sex != ''
|
||||||
ORDER BY name
|
ORDER BY name
|
||||||
@ -263,7 +264,7 @@ ORDER BY name
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address
|
SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address, family_id
|
||||||
FROM user
|
FROM user
|
||||||
WHERE deleted = 0 AND (SELECT COUNT(*) FROM user_role WHERE user_id=user.id AND role_id = (SELECT id FROM role WHERE name = 'cox')) > 0
|
WHERE deleted = 0 AND (SELECT COUNT(*) FROM user_role WHERE user_id=user.id AND role_id = (SELECT id FROM role WHERE name = 'cox')) > 0
|
||||||
ORDER BY last_access DESC
|
ORDER BY last_access DESC
|
||||||
@ -282,8 +283,14 @@ ORDER BY last_access DESC
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update(&self, db: &SqlitePool, data: UserEditForm) {
|
pub async fn update(&self, db: &SqlitePool, data: UserEditForm) {
|
||||||
|
let mut family_id = data.family_id;
|
||||||
|
|
||||||
|
if family_id.is_some_and(|x| x == -1) {
|
||||||
|
family_id = Some(Family::new(db).await)
|
||||||
|
}
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"UPDATE user SET dob = ?, weight = ?, sex = ?, member_since_date=?, birthdate=?, mail=?, nickname=?, notes=?, phone=?, address=? where id = ?",
|
"UPDATE user SET dob = ?, weight = ?, sex = ?, member_since_date=?, birthdate=?, mail=?, nickname=?, notes=?, phone=?, address=?, family_id = ? where id = ?",
|
||||||
data.dob,
|
data.dob,
|
||||||
data.weight,
|
data.weight,
|
||||||
data.sex,
|
data.sex,
|
||||||
@ -294,6 +301,7 @@ ORDER BY last_access DESC
|
|||||||
data.notes,
|
data.notes,
|
||||||
data.phone,
|
data.phone,
|
||||||
data.address,
|
data.address,
|
||||||
|
family_id,
|
||||||
self.id
|
self.id
|
||||||
)
|
)
|
||||||
.execute(db)
|
.execute(db)
|
||||||
@ -714,6 +722,7 @@ mod test {
|
|||||||
notes: None,
|
notes: None,
|
||||||
phone: None,
|
phone: None,
|
||||||
address: None,
|
address: None,
|
||||||
|
family_id: None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::model::{
|
use crate::model::{
|
||||||
|
family::Family,
|
||||||
role::Role,
|
role::Role,
|
||||||
user::{AdminUser, User, UserWithRoles},
|
user::{AdminUser, User, UserWithRoles},
|
||||||
};
|
};
|
||||||
@ -30,6 +31,7 @@ async fn index(
|
|||||||
let users: Vec<UserWithRoles> = join_all(user_futures).await;
|
let users: Vec<UserWithRoles> = join_all(user_futures).await;
|
||||||
|
|
||||||
let roles = Role::all(db).await;
|
let roles = Role::all(db).await;
|
||||||
|
let families = Family::all_with_members(db).await;
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
if let Some(msg) = flash {
|
if let Some(msg) = flash {
|
||||||
@ -37,6 +39,7 @@ async fn index(
|
|||||||
}
|
}
|
||||||
context.insert("users", &users);
|
context.insert("users", &users);
|
||||||
context.insert("roles", &roles);
|
context.insert("roles", &roles);
|
||||||
|
context.insert("families", &families);
|
||||||
context.insert(
|
context.insert(
|
||||||
"loggedin_user",
|
"loggedin_user",
|
||||||
&UserWithRoles::from_user(admin.user, db).await,
|
&UserWithRoles::from_user(admin.user, db).await,
|
||||||
@ -89,6 +92,7 @@ pub struct UserEditForm {
|
|||||||
pub(crate) notes: Option<String>,
|
pub(crate) notes: Option<String>,
|
||||||
pub(crate) phone: Option<String>,
|
pub(crate) phone: Option<String>,
|
||||||
pub(crate) address: Option<String>,
|
pub(crate) address: Option<String>,
|
||||||
|
pub(crate) family_id: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/user", data = "<data>")]
|
#[post("/user", data = "<data>")]
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS "family" (
|
||||||
|
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "user" ADD COLUMN "family_id" INTEGER REFERENCES family(id);
|
@ -72,6 +72,7 @@
|
|||||||
{{ macros::input(label='Notizen', name='notes', id=loop.index, type="text", value=user.notes) }}
|
{{ macros::input(label='Notizen', name='notes', id=loop.index, type="text", value=user.notes) }}
|
||||||
{{ macros::input(label='Telefon', name='phone', id=loop.index, type="text", value=user.phone) }}
|
{{ macros::input(label='Telefon', name='phone', id=loop.index, type="text", value=user.phone) }}
|
||||||
{{ macros::input(label='Adresse', name='address', id=loop.index, type="text", value=user.address) }}
|
{{ macros::input(label='Adresse', name='address', id=loop.index, type="text", value=user.address) }}
|
||||||
|
{{ macros::select(label="Familie", data=families, name='family_id', selected_id=user.family_id, display=['names'], default="Keine Familie", new_last_entry='Neue Familie anlegen') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 text-right">
|
<div class="mt-3 text-right">
|
||||||
|
@ -164,7 +164,7 @@
|
|||||||
</label>
|
</label>
|
||||||
{% endmacro checkbox %}
|
{% endmacro checkbox %}
|
||||||
|
|
||||||
{% macro select(label, data, name='trip_type', default='', id='', selected_id='', display='', extras='', class='', wrapper_class='', required=false, show_seats=false) %}
|
{% macro select(label, data, name='trip_type', default='', id='', selected_id='', display='', extras='', class='', wrapper_class='', required=false, show_seats=false, new_last_entry='') %}
|
||||||
<div class="{{wrapper_class}}">
|
<div class="{{wrapper_class}}">
|
||||||
<label for="{{ name }}" class="text-sm text-gray-600 dark:text-gray-100">{{ label }}</label>
|
<label for="{{ name }}" class="text-sm text-gray-600 dark:text-gray-100">{{ label }}</label>
|
||||||
{% if display == '' %}
|
{% if display == '' %}
|
||||||
@ -185,11 +185,13 @@
|
|||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
</option>
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if new_last_entry %}
|
||||||
|
<option value="-1">{{ new_last_entry }}</option>
|
||||||
|
{% endif %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{% endmacro select %}
|
{% endmacro select %}
|
||||||
|
|
||||||
|
|
||||||
{% macro alert(message, type, class='') %}
|
{% macro alert(message, type, class='') %}
|
||||||
<div class="{{ class }} alert-{{ type }} text-white px-3 py-1 rounded-md text-center">
|
<div class="{{ class }} alert-{{ type }} text-white px-3 py-1 rounded-md text-center">
|
||||||
{{ message }}
|
{{ message }}
|
||||||
|
Loading…
Reference in New Issue
Block a user