Be able to update financial and skill; Fixes #974
This commit is contained in:
parent
905178e60d
commit
6362fed909
@ -1,4 +1,4 @@
|
|||||||
use std::{fmt::Display, ops::DerefMut};
|
use std::{cmp::Ordering, fmt::Display, ops::DerefMut};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||||
@ -13,6 +13,30 @@ pub struct Role {
|
|||||||
pub(crate) cluster: Option<String>,
|
pub(crate) cluster: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implement PartialEq to compare roles based only on id
|
||||||
|
impl PartialEq for Role {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.id == other.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement Eq to indicate that equality is reflexive
|
||||||
|
impl Eq for Role {}
|
||||||
|
|
||||||
|
// Implement PartialOrd if you need to sort or compare roles
|
||||||
|
impl PartialOrd for Role {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.id.cmp(&other.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement Ord if you need total ordering (for sorting)
|
||||||
|
impl Ord for Role {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.id.cmp(&other.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Role {
|
impl Display for Role {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}", self.name)
|
write!(f, "{}", self.name)
|
||||||
@ -30,6 +54,27 @@ impl Role {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn all_cluster(db: &SqlitePool, cluster: &str) -> Vec<Role> {
|
||||||
|
sqlx::query_as!(
|
||||||
|
Role,
|
||||||
|
r#"SELECT id,
|
||||||
|
CASE WHEN formatted_name IS NOT NULL AND formatted_name != ''
|
||||||
|
THEN formatted_name
|
||||||
|
ELSE name
|
||||||
|
END AS "name!: String",
|
||||||
|
'' as formatted_name,
|
||||||
|
desc,
|
||||||
|
hide_in_lists,
|
||||||
|
cluster
|
||||||
|
FROM role
|
||||||
|
WHERE cluster = ?"#,
|
||||||
|
cluster
|
||||||
|
)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn find_by_id(db: &SqlitePool, name: i32) -> Option<Self> {
|
pub async fn find_by_id(db: &SqlitePool, name: i32) -> Option<Self> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
@ -59,21 +104,6 @@ WHERE id like ?
|
|||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_by_cluster_tx(db: &mut Transaction<'_, Sqlite>, name: i32) -> Option<Self> {
|
|
||||||
sqlx::query_as!(
|
|
||||||
Self,
|
|
||||||
"
|
|
||||||
SELECT id, name, formatted_name, desc, hide_in_lists, cluster
|
|
||||||
FROM role
|
|
||||||
WHERE cluster = ?
|
|
||||||
",
|
|
||||||
name
|
|
||||||
)
|
|
||||||
.fetch_one(db.deref_mut())
|
|
||||||
.await
|
|
||||||
.ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn find_by_name(db: &SqlitePool, name: &str) -> Option<Self> {
|
pub async fn find_by_name(db: &SqlitePool, name: &str) -> Option<Self> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
// 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::{activity::Activity, family::Family, log::Log, mail::valid_mails, role::Role};
|
use crate::model::{
|
||||||
|
activity::Activity, family::Family, log::Log, mail::valid_mails, notification::Notification,
|
||||||
|
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;
|
||||||
@ -228,6 +231,103 @@ impl User {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn change_skill(
|
||||||
|
&self,
|
||||||
|
db: &SqlitePool,
|
||||||
|
updated_by: &ManageUserUser,
|
||||||
|
skill: Option<Role>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let old_skill = self.skill(db).await;
|
||||||
|
|
||||||
|
let member = Role::find_by_name(db, "Donau Linz").await.unwrap();
|
||||||
|
let cox = Role::find_by_name(db, "cox").await.unwrap();
|
||||||
|
let bootsfuehrer = Role::find_by_name(db, "Bootsführer").await.unwrap();
|
||||||
|
|
||||||
|
match (old_skill, skill) {
|
||||||
|
(old, new) if old == None && new == Some(cox.clone()) => {
|
||||||
|
self.add_role(db, updated_by, &cox).await?;
|
||||||
|
Notification::create_for_role(
|
||||||
|
db,
|
||||||
|
&member,
|
||||||
|
&format!(
|
||||||
|
"Liebes Vereinsmitglied, {self} ist ab sofort Steuerperson 🎉 Hip hip ...!"
|
||||||
|
),
|
||||||
|
"Neue Steuerperson",
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
(old, new) if old == Some(cox.clone()) && new == Some(bootsfuehrer.clone()) => {
|
||||||
|
self.remove_role(db, updated_by, &cox).await?;
|
||||||
|
self.add_role(db, updated_by, &bootsfuehrer).await?;
|
||||||
|
Notification::create_for_role(
|
||||||
|
db,
|
||||||
|
&member,
|
||||||
|
&format!(
|
||||||
|
"Liebes Vereinsmitglied, {self} ist ab sofort Bootsführer:in 🎉 Hip hip ...!"
|
||||||
|
),
|
||||||
|
"Neue:r Bootsführer:in",
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
(old, new) if new == None => {
|
||||||
|
if let Some(old) = old {
|
||||||
|
self.remove_role(db, updated_by, &old).await?;
|
||||||
|
let vorstand = Role::find_by_name(db, "Vorstand").await.unwrap();
|
||||||
|
Notification::create_for_role(
|
||||||
|
db,
|
||||||
|
&vorstand,
|
||||||
|
&format!("Lieber Vorstand, {self} ist ab kein {old} mehr."),
|
||||||
|
"Steuerperson --",
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(old, new) => return Err(format!("Not allowed to change from {old:?} to {new:?}")),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn change_financial(
|
||||||
|
&self,
|
||||||
|
db: &SqlitePool,
|
||||||
|
updated_by: &ManageUserUser,
|
||||||
|
financial: Option<Role>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let mut new = String::new();
|
||||||
|
let mut old = String::new();
|
||||||
|
|
||||||
|
if let Some(old_financial) = self.financial(db).await {
|
||||||
|
self.remove_role(db, updated_by, &old_financial).await?;
|
||||||
|
old.push_str(&old_financial.name);
|
||||||
|
} else {
|
||||||
|
old.push_str("Keine Ermäßigung");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(new_financial) = financial {
|
||||||
|
self.add_role(db, updated_by, &new_financial).await?;
|
||||||
|
new.push_str(&new_financial.name);
|
||||||
|
} else {
|
||||||
|
new.push_str("Keine Ermäßigung");
|
||||||
|
}
|
||||||
|
|
||||||
|
Activity::create(
|
||||||
|
db,
|
||||||
|
&format!("({updated_by}) Ermäßigung von {self} von {old} auf {new} geändert"),
|
||||||
|
&format!("user-{};", self.id),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn remove_role(
|
pub(crate) async fn remove_role(
|
||||||
&self,
|
&self,
|
||||||
db: &SqlitePool,
|
db: &SqlitePool,
|
||||||
|
@ -259,6 +259,39 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
.into_iter().map(|r| r.name).collect()
|
.into_iter().map(|r| r.name).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn financial(&self, db: &SqlitePool) -> Option<Role> {
|
||||||
|
sqlx::query_as!(
|
||||||
|
Role,
|
||||||
|
"
|
||||||
|
SELECT r.id, r.name, r.formatted_name, r.desc, r.hide_in_lists, r.cluster
|
||||||
|
FROM role r
|
||||||
|
JOIN user_role ur ON r.id = ur.role_id
|
||||||
|
WHERE ur.user_id = ?
|
||||||
|
AND r.cluster = 'financial';
|
||||||
|
",
|
||||||
|
self.id
|
||||||
|
)
|
||||||
|
.fetch_optional(db)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
pub async fn skill(&self, db: &SqlitePool) -> Option<Role> {
|
||||||
|
sqlx::query_as!(
|
||||||
|
Role,
|
||||||
|
"
|
||||||
|
SELECT r.id, r.name, r.formatted_name, r.desc, r.hide_in_lists, r.cluster
|
||||||
|
FROM role r
|
||||||
|
JOIN user_role ur ON r.id = ur.role_id
|
||||||
|
WHERE ur.user_id = ?
|
||||||
|
AND r.cluster = 'skill';
|
||||||
|
",
|
||||||
|
self.id
|
||||||
|
)
|
||||||
|
.fetch_optional(db)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn real_roles(&self, db: &SqlitePool) -> Vec<Role> {
|
pub async fn real_roles(&self, db: &SqlitePool) -> Vec<Role> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Role,
|
Role,
|
||||||
|
@ -130,6 +130,10 @@ async fn view(
|
|||||||
let member = Member::from(db, user.clone()).await;
|
let member = Member::from(db, user.clone()).await;
|
||||||
let fee = user.fee(db).await;
|
let fee = user.fee(db).await;
|
||||||
let activities = Activity::for_user(db, &user).await;
|
let activities = Activity::for_user(db, &user).await;
|
||||||
|
let financial = Role::all_cluster(db, "financial").await;
|
||||||
|
let user_financial = user.financial(db).await;
|
||||||
|
let skill = Role::all_cluster(db, "skill").await;
|
||||||
|
let user_skill = user.skill(db).await;
|
||||||
|
|
||||||
let user = UserWithRolesAndMembershipPdf::from_user(db, user).await;
|
let user = UserWithRolesAndMembershipPdf::from_user(db, user).await;
|
||||||
|
|
||||||
@ -148,6 +152,10 @@ async fn view(
|
|||||||
context.insert("is_clubmember", &member.is_club_member());
|
context.insert("is_clubmember", &member.is_club_member());
|
||||||
context.insert("supposed_to_pay", &member.supposed_to_pay());
|
context.insert("supposed_to_pay", &member.supposed_to_pay());
|
||||||
context.insert("fee", &fee);
|
context.insert("fee", &fee);
|
||||||
|
context.insert("skill", &skill);
|
||||||
|
context.insert("user_skill", &user_skill);
|
||||||
|
context.insert("financial", &financial);
|
||||||
|
context.insert("user_financial", &user_financial);
|
||||||
context.insert("member", &member);
|
context.insert("member", &member);
|
||||||
context.insert("activities", &activities);
|
context.insert("activities", &activities);
|
||||||
context.insert("roles", &roles);
|
context.insert("roles", &roles);
|
||||||
@ -456,6 +464,86 @@ async fn update_family(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm, Debug)]
|
||||||
|
pub struct ChangeSkillForm {
|
||||||
|
skill_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/user/<id>/change-skill", data = "<data>")]
|
||||||
|
async fn change_skill(
|
||||||
|
db: &State<SqlitePool>,
|
||||||
|
data: Form<ChangeSkillForm>,
|
||||||
|
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),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let skill = if &data.skill_id == "" {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let Ok(skill_id) = data.skill_id.parse() else {
|
||||||
|
return Flash::error(
|
||||||
|
Redirect::to(format!("/admin/user/{id}")),
|
||||||
|
format!("Skill_id is not a number"),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
Role::find_by_id(db, skill_id).await
|
||||||
|
};
|
||||||
|
|
||||||
|
match user.change_skill(db, &admin, skill).await {
|
||||||
|
Ok(()) => Flash::success(
|
||||||
|
Redirect::to(format!("/admin/user/{}", user.id)),
|
||||||
|
"Skill erfolgreich geändert",
|
||||||
|
),
|
||||||
|
Err(e) => Flash::error(Redirect::to(format!("/admin/user/{}", user.id)), e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm, Debug)]
|
||||||
|
pub struct ChangeFinancialForm {
|
||||||
|
financial_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/user/<id>/change-financial", data = "<data>")]
|
||||||
|
async fn change_financial(
|
||||||
|
db: &State<SqlitePool>,
|
||||||
|
data: Form<ChangeFinancialForm>,
|
||||||
|
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),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let financial = if &data.financial_id == "" {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let Ok(financial_id) = data.financial_id.parse() else {
|
||||||
|
return Flash::error(
|
||||||
|
Redirect::to(format!("/admin/user/{id}")),
|
||||||
|
format!("Finacial_id is not a number"),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
Role::find_by_id(db, financial_id).await
|
||||||
|
};
|
||||||
|
|
||||||
|
match user.change_financial(db, &admin, financial).await {
|
||||||
|
Ok(()) => Flash::success(
|
||||||
|
Redirect::to(format!("/admin/user/{}", user.id)),
|
||||||
|
"Ermäßigung erfolgreich geändert",
|
||||||
|
),
|
||||||
|
Err(e) => Flash::error(Redirect::to(format!("/admin/user/{}", user.id)), e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(FromForm, Debug)]
|
#[derive(FromForm, Debug)]
|
||||||
pub struct AddMembershipPDFForm<'a> {
|
pub struct AddMembershipPDFForm<'a> {
|
||||||
membership_pdf: TempFile<'a>,
|
membership_pdf: TempFile<'a>,
|
||||||
@ -1176,6 +1264,8 @@ pub fn routes() -> Vec<Route> {
|
|||||||
update_birthdate,
|
update_birthdate,
|
||||||
update_address,
|
update_address,
|
||||||
update_family,
|
update_family,
|
||||||
|
change_skill,
|
||||||
|
change_financial,
|
||||||
add_membership_pdf,
|
add_membership_pdf,
|
||||||
add_role,
|
add_role,
|
||||||
add_note,
|
add_note,
|
||||||
|
@ -33,3 +33,4 @@ CREATE TABLE activity (
|
|||||||
relevant_for TEXT NOT NULL, -- e.g. user_id=123;trip_id=456
|
relevant_for TEXT NOT NULL, -- e.g. user_id=123;trip_id=456
|
||||||
keep_until DATETIME -- OPTIONAL field
|
keep_until DATETIME -- OPTIONAL field
|
||||||
);
|
);
|
||||||
|
delete from role where name='Anwärter';
|
||||||
|
@ -31,6 +31,13 @@
|
|||||||
<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>
|
||||||
|
<form action="/admin/user/{{ user.id }}/change-financial" method="post">
|
||||||
|
{% if user_financial %}
|
||||||
|
{{ macros::selectgroup(label="Finanzielles", data=financial, selected_id=user_financial.id, name='financial_id', display=['name'], default="Keine Ermäßigung", readonly=not allowed_to_edit) }}
|
||||||
|
{% else %}
|
||||||
|
{{ macros::selectgroup(label="Finanzielles", data=financial, name='financial_id', display=['name'], default="Keine Ermäßigung", readonly=not allowed_to_edit) }}
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
{% if allowed_to_edit %}
|
{% if allowed_to_edit %}
|
||||||
<form action="/admin/user/{{ user.id }}/new-note" method="post">
|
<form action="/admin/user/{{ user.id }}/new-note" method="post">
|
||||||
{{ macros::inputgroup(label='Neue Notiz', name='note', type="text") }}
|
{{ macros::inputgroup(label='Neue Notiz', name='note', type="text") }}
|
||||||
@ -79,6 +86,14 @@
|
|||||||
<form action="/admin/user/{{ user.id }}/change-address" method="post">
|
<form action="/admin/user/{{ user.id }}/change-address" method="post">
|
||||||
{{ macros::inputgroup(label='Adresse', name='address', type="text", value=user.address, readonly=not allowed_to_edit) }}
|
{{ macros::inputgroup(label='Adresse', name='address', type="text", value=user.address, readonly=not allowed_to_edit) }}
|
||||||
</form>
|
</form>
|
||||||
|
<form action="/admin/user/{{ user.id }}/change-skill" method="post">
|
||||||
|
{% if user_skill %}
|
||||||
|
{{ macros::selectgroup(label="Steuererlaubnis", data=skill, selected_id=user_skill.id, name='skill_id', display=['name'], default="Keine Steuerberechtigung", readonly=not allowed_to_edit) }}
|
||||||
|
{% else %}
|
||||||
|
{{ macros::selectgroup(label="Steuererlaubnis", data=skill, name='skill_id', display=['name'], default="Keine Steuerberechtigung", readonly=not allowed_to_edit) }}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
<form action="/admin/user/{{ user.id }}/change-family" method="post">
|
<form action="/admin/user/{{ user.id }}/change-family" method="post">
|
||||||
{{ macros::selectgroup(label="Familie", data=families, name='family_id', selected_id=user.family_id, display=['names'], default="Keine Familie", new_last_entry='Neue Familie anlegen', readonly=not allowed_to_edit) }}
|
{{ macros::selectgroup(label="Familie", data=families, name='family_id', selected_id=user.family_id, display=['names'], default="Keine Familie", new_last_entry='Neue Familie anlegen', readonly=not allowed_to_edit) }}
|
||||||
</form>
|
</form>
|
||||||
@ -398,64 +413,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5">
|
|
||||||
<h2 class="h2">TODO</h2>
|
|
||||||
<div class="border-t bg-white dark:bg-primary-900 py-3 px-4 relative">
|
|
||||||
<span class="text-black dark:text-white cursor-pointer">
|
|
||||||
<span class="font-bold">
|
|
||||||
{{ user.name }}
|
|
||||||
{% if not user.last_access and allowed_to_edit and user.mail %}
|
|
||||||
<form action="/admin/user"
|
|
||||||
method="post"
|
|
||||||
enctype="multipart/form-data"
|
|
||||||
class="inline">
|
|
||||||
• <a class="font-normal text-primary-600 dark:text-primary-200 hover:text-primary-900 dark:hover:text-primary-300 underline"
|
|
||||||
href="/admin/user/{{ user.id }}/send-welcome-mail"
|
|
||||||
onclick="return confirm('Willst du wirklich das Willkommensmail an {{ user.name }} ausschicken?');">Willkommensmail verschicken</a>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<form action="/admin/user"
|
|
||||||
method="post"
|
|
||||||
enctype="multipart/form-data"
|
|
||||||
class="w-full mt-2">
|
|
||||||
<div class="w-full grid gap-3 mt-3">
|
|
||||||
<input type="hidden" name="id" value="{{ user.id }}" />
|
|
||||||
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-3">
|
|
||||||
{% for cluster, cluster_roles in roles | group_by(attribute="cluster") %}
|
|
||||||
<label for="cluster_{{ loop.index }}">{{ cluster }}</label>
|
|
||||||
{# Determine the initially selected role within the cluster #}
|
|
||||||
{% set_global selected_role_id = "none" %}
|
|
||||||
{% for role in cluster_roles %}
|
|
||||||
{% if selected_role_id == "none" and role.name in user.roles %}
|
|
||||||
{% set_global selected_role_id = role.id %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{# Set default name to the selected role ID or first role if none selected #}
|
|
||||||
<select id="cluster_{{ loop.index }}"
|
|
||||||
{% if selected_role_id == 'none' %} {% else %} name="roles[{{ selected_role_id }}]" {% endif %}
|
|
||||||
{% if allowed_to_edit == false %}disabled{% endif %}
|
|
||||||
onchange=" if (this.value === '') { this.removeAttribute('name'); } else { this.name = 'roles[' + this.options[this.selectedIndex].getAttribute('data-role-id') + ']'; }">
|
|
||||||
<option value=""
|
|
||||||
data-role-id="none"
|
|
||||||
{% if selected_role_id == 'none' %}selected="selected"{% endif %}>
|
|
||||||
None
|
|
||||||
</option>
|
|
||||||
{% for role in cluster_roles %}
|
|
||||||
<option value="on"
|
|
||||||
data-role-id="{{ role.id }}"
|
|
||||||
{% if role.id == selected_role_id %}selected="selected"{% endif %}>
|
|
||||||
{{ role.name }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5">
|
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5">
|
||||||
<h2 class="h2">Ergo-Challenge</h2>
|
<h2 class="h2">Ergo-Challenge</h2>
|
||||||
<div class="mx-3 divide-y divide-gray-200 dark:divide-primary-600">
|
<div class="mx-3 divide-y divide-gray-200 dark:divide-primary-600">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user