start with activity + fix tests
This commit is contained in:
parent
d50501b362
commit
e360c4f06b
@ -225,6 +225,15 @@ CREATE TABLE IF NOT EXISTS "distance" (
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "activity" (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
text TEXT NOT NULL,
|
||||||
|
relevant_for TEXT NOT NULL, -- e.g. user_id=123;trip_id=456
|
||||||
|
keep_until DATETIME
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
CREATE TRIGGER IF NOT EXISTS prevent_multiple_roles_same_cluster
|
CREATE TRIGGER IF NOT EXISTS prevent_multiple_roles_same_cluster
|
||||||
BEFORE INSERT ON user_role
|
BEFORE INSERT ON user_role
|
||||||
BEGIN
|
BEGIN
|
||||||
|
54
src/model/activity.rs
Normal file
54
src/model/activity.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
|
use chrono::NaiveDateTime;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||||
|
|
||||||
|
#[derive(FromRow, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct Activity {
|
||||||
|
pub id: i64,
|
||||||
|
pub created_at: NaiveDateTime,
|
||||||
|
pub text: String,
|
||||||
|
pub relevant_for: String,
|
||||||
|
pub keep_until: Option<NaiveDateTime>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Activity {
|
||||||
|
pub async fn find_by_id(db: &SqlitePool, id: i64) -> Option<Self> {
|
||||||
|
sqlx::query_as!(
|
||||||
|
Self,
|
||||||
|
"SELECT id, created_at, text, relevant_for, keep_until FROM activity WHERE id like ?",
|
||||||
|
id
|
||||||
|
)
|
||||||
|
.fetch_one(db)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
pub async fn create_with_tx(
|
||||||
|
db: &mut Transaction<'_, Sqlite>,
|
||||||
|
text: &str,
|
||||||
|
relevant_for: &str,
|
||||||
|
keep_until: Option<NaiveDateTime>,
|
||||||
|
) {
|
||||||
|
sqlx::query!(
|
||||||
|
"INSERT INTO activity(text, relevant_for, keep_until) VALUES (?, ?, ?)",
|
||||||
|
text,
|
||||||
|
relevant_for,
|
||||||
|
keep_until
|
||||||
|
)
|
||||||
|
.execute(db.deref_mut())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create(
|
||||||
|
db: &SqlitePool,
|
||||||
|
text: &str,
|
||||||
|
relevant_for: &str,
|
||||||
|
keep_until: Option<NaiveDateTime>,
|
||||||
|
) {
|
||||||
|
let mut tx = db.begin().await.unwrap();
|
||||||
|
Self::create_with_tx(&mut tx, text, relevant_for, keep_until).await;
|
||||||
|
tx.commit().await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ use self::{
|
|||||||
use boatreservation::{BoatReservation, BoatReservationWithDetails};
|
use boatreservation::{BoatReservation, BoatReservationWithDetails};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub mod activity;
|
||||||
pub mod boat;
|
pub mod boat;
|
||||||
pub mod boatdamage;
|
pub mod boatdamage;
|
||||||
pub mod boathouse;
|
pub mod boathouse;
|
||||||
|
@ -1,12 +1,25 @@
|
|||||||
// TODO: put back in `src/model/user/mod.rs` once that is cleaned up
|
// TODO: put back in `src/model/user/mod.rs` once that is cleaned up
|
||||||
|
|
||||||
use super::{AllowedToEditPaymentStatusUser, ManageUserUser, User};
|
use super::{AllowedToEditPaymentStatusUser, ManageUserUser, User};
|
||||||
use crate::model::{family::Family, log::Log, mail::valid_mails, role::Role};
|
use crate::model::{activity::Activity, family::Family, log::Log, mail::valid_mails, role::Role};
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use rocket::{fs::TempFile, tokio::io::AsyncReadExt};
|
use rocket::{fs::TempFile, tokio::io::AsyncReadExt};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
|
pub(crate) async fn add_note(
|
||||||
|
&self,
|
||||||
|
db: &SqlitePool,
|
||||||
|
updated_by: &ManageUserUser,
|
||||||
|
note: &str,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let note = note.trim();
|
||||||
|
|
||||||
|
Activity::create(db, note, "relevant_for", None).await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn update_mail(
|
pub(crate) async fn update_mail(
|
||||||
&self,
|
&self,
|
||||||
db: &SqlitePool,
|
db: &SqlitePool,
|
||||||
|
@ -951,9 +951,7 @@ impl UserWithMembershipPdf {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::collections::HashMap;
|
use crate::testdb;
|
||||||
|
|
||||||
use crate::{tera::admin::user::UserEditForm, testdb};
|
|
||||||
|
|
||||||
use super::User;
|
use super::User;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
@ -1014,38 +1012,6 @@ mod test {
|
|||||||
assert_eq!(User::create(&pool, "admin".into()).await, false);
|
assert_eq!(User::create(&pool, "admin".into()).await, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[sqlx::test]
|
|
||||||
fn test_update() {
|
|
||||||
let pool = testdb!();
|
|
||||||
|
|
||||||
let user = User::find_by_id(&pool, 1).await.unwrap();
|
|
||||||
user.update(
|
|
||||||
&pool,
|
|
||||||
UserEditForm {
|
|
||||||
id: 1,
|
|
||||||
dob: None,
|
|
||||||
weight: None,
|
|
||||||
sex: Some("m".into()),
|
|
||||||
roles: HashMap::new(),
|
|
||||||
member_since_date: None,
|
|
||||||
birthdate: None,
|
|
||||||
mail: None,
|
|
||||||
nickname: None,
|
|
||||||
notes: None,
|
|
||||||
phone: None,
|
|
||||||
address: None,
|
|
||||||
family_id: None,
|
|
||||||
membership_pdf: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let user = User::find_by_id(&pool, 1).await.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(user.sex, Some("m".into()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[sqlx::test]
|
#[sqlx::test]
|
||||||
fn succ_login_with_test_db() {
|
fn succ_login_with_test_db() {
|
||||||
let pool = testdb!();
|
let pool = testdb!();
|
||||||
|
@ -327,6 +327,34 @@ async fn update_mail(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm, Debug)]
|
||||||
|
pub struct AddNoteForm {
|
||||||
|
note: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/user/<id>/add-note", data = "<data>")]
|
||||||
|
async fn add_note(
|
||||||
|
db: &State<SqlitePool>,
|
||||||
|
data: Form<AddNoteForm>,
|
||||||
|
admin: ManageUserUser,
|
||||||
|
id: i32,
|
||||||
|
) -> Flash<Redirect> {
|
||||||
|
let Some(user) = User::find_by_id(db, id).await else {
|
||||||
|
return Flash::error(
|
||||||
|
Redirect::to("/admin/user"),
|
||||||
|
format!("User with ID {} does not exist!", id),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
match user.add_note(db, &admin, &data.note).await {
|
||||||
|
Ok(_) => Flash::success(
|
||||||
|
Redirect::to(format!("/admin/user/{}", user.id)),
|
||||||
|
"Notiz hinzugefügt",
|
||||||
|
),
|
||||||
|
Err(e) => Flash::error(Redirect::to(format!("/admin/user/{}", user.id)), e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(FromForm, Debug)]
|
#[derive(FromForm, Debug)]
|
||||||
pub struct PhoneUpdateForm {
|
pub struct PhoneUpdateForm {
|
||||||
phone: String,
|
phone: String,
|
||||||
@ -1147,6 +1175,7 @@ pub fn routes() -> Vec<Route> {
|
|||||||
update_family,
|
update_family,
|
||||||
add_membership_pdf,
|
add_membership_pdf,
|
||||||
add_role,
|
add_role,
|
||||||
|
add_note,
|
||||||
remove_role,
|
remove_role,
|
||||||
//
|
//
|
||||||
scheckbook_to_regular,
|
scheckbook_to_regular,
|
||||||
|
@ -25,3 +25,11 @@ UPDATE role SET desc='Es können Logbucheinträge im Nachhinein hinzugefügt wer
|
|||||||
UPDATE role SET desc='Erlaubt den Login auf der Wordpress-Website um zB Artikel zu schreiben.' WHERE name='allow_website_login';
|
UPDATE role SET desc='Erlaubt den Login auf der Wordpress-Website um zB Artikel zu schreiben.' WHERE name='allow_website_login';
|
||||||
UPDATE role SET desc='Muss nur den halben Rennruderbeitrag bezahlen (da zB erst in der 2. Jahreshälfte dazugestoßen wurde)' WHERE name='half-rennrudern';
|
UPDATE role SET desc='Muss nur den halben Rennruderbeitrag bezahlen (da zB erst in der 2. Jahreshälfte dazugestoßen wurde)' WHERE name='half-rennrudern';
|
||||||
UPDATE role SET desc='Muss keinen Rennruderbeitrag bezahlen, obwohl man in Rennruder-Gruppe ist.' WHERE name='renntrainer';
|
UPDATE role SET desc='Muss keinen Rennruderbeitrag bezahlen, obwohl man in Rennruder-Gruppe ist.' WHERE name='renntrainer';
|
||||||
|
|
||||||
|
CREATE TABLE activity (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
text TEXT NOT NULL,
|
||||||
|
relevant_for TEXT NOT NULL, -- e.g. user_id=123;trip_id=456
|
||||||
|
keep_until DATETIME -- OPTIONAL field
|
||||||
|
);
|
||||||
|
@ -31,6 +31,11 @@
|
|||||||
<form action="/admin/user/{{ user.id }}/change-nickname" method="post">
|
<form action="/admin/user/{{ user.id }}/change-nickname" method="post">
|
||||||
{{ macros::inputgroup(label='Spitzname', name='nickname', type="text", value=user.nickname, readonly=not allowed_to_edit) }}
|
{{ macros::inputgroup(label='Spitzname', name='nickname', type="text", value=user.nickname, readonly=not allowed_to_edit) }}
|
||||||
</form>
|
</form>
|
||||||
|
{% if allowed_to_edit %}
|
||||||
|
<form action="/admin/user/{{ user.id }}/new-note" method="post">
|
||||||
|
{{ macros::inputgroup(label='Neue Notiz', name='note', type="text") }}
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
<span>Notizen: to be replaced with activity :-)</span>
|
<span>Notizen: to be replaced with activity :-)</span>
|
||||||
{% if user.pw and allowed_to_edit %}
|
{% if user.pw and allowed_to_edit %}
|
||||||
<div>
|
<div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user