Refactor: Name-Feld entfernen, Email als einziger Identifier
- Name-Spalte aus Nutzertabelle entfernt - Anzeigename-Feld aus Nutzer-Anlegen-Dialog entfernt - Username wird automatisch aus Email-Prefix generiert - UserCreate Model: username jetzt optional Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -56,7 +56,7 @@ class LicenseResponse(BaseModel):
|
|||||||
|
|
||||||
class UserCreate(BaseModel):
|
class UserCreate(BaseModel):
|
||||||
email: str = Field(min_length=3, max_length=200)
|
email: str = Field(min_length=3, max_length=200)
|
||||||
username: str = Field(min_length=1, max_length=100)
|
username: Optional[str] = Field(default=None, max_length=100)
|
||||||
role: str = Field(default="member", pattern="^(org_admin|member)$")
|
role: str = Field(default="member", pattern="^(org_admin|member)$")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -66,11 +66,12 @@ async def create_user(
|
|||||||
if await cursor.fetchone():
|
if await cursor.fetchone():
|
||||||
raise HTTPException(status_code=400, detail="E-Mail bereits vergeben")
|
raise HTTPException(status_code=400, detail="E-Mail bereits vergeben")
|
||||||
|
|
||||||
|
username = data.username if data.username else email.split("@")[0]
|
||||||
now = datetime.now(timezone.utc).isoformat()
|
now = datetime.now(timezone.utc).isoformat()
|
||||||
cursor = await db.execute(
|
cursor = await db.execute(
|
||||||
"""INSERT INTO users (email, username, password_hash, organization_id, role, is_active, created_at)
|
"""INSERT INTO users (email, username, password_hash, organization_id, role, is_active, created_at)
|
||||||
VALUES (?, ?, '', ?, ?, 1, ?)""",
|
VALUES (?, ?, '', ?, ?, 1, ?)""",
|
||||||
(email, data.username, org_id, data.role, now),
|
(email, username, org_id, data.role, now),
|
||||||
)
|
)
|
||||||
user_id = cursor.lastrowid
|
user_id = cursor.lastrowid
|
||||||
|
|
||||||
@@ -91,7 +92,7 @@ async def create_user(
|
|||||||
from email_utils.sender import send_email
|
from email_utils.sender import send_email
|
||||||
from email_utils.templates import invite_email
|
from email_utils.templates import invite_email
|
||||||
link = f"{MAGIC_LINK_BASE_URL}/auth/verify?token={token}"
|
link = f"{MAGIC_LINK_BASE_URL}/auth/verify?token={token}"
|
||||||
subject, html = invite_email(data.username, org["name"], code, link)
|
subject, html = invite_email(username, org["name"], code, link)
|
||||||
await send_email(email, subject, html)
|
await send_email(email, subject, html)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # E-Mail-Fehler nicht fatal
|
pass # E-Mail-Fehler nicht fatal
|
||||||
|
|||||||
@@ -101,7 +101,6 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>E-Mail</th>
|
<th>E-Mail</th>
|
||||||
<th>Name</th>
|
|
||||||
<th>Rolle</th>
|
<th>Rolle</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Aktionen</th>
|
<th>Aktionen</th>
|
||||||
@@ -234,10 +233,6 @@
|
|||||||
<label for="newUserEmail">E-Mail</label>
|
<label for="newUserEmail">E-Mail</label>
|
||||||
<input type="email" id="newUserEmail" required>
|
<input type="email" id="newUserEmail" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<label for="newUserName">Anzeigename</label>
|
|
||||||
<input type="text" id="newUserName" required>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="newUserRole">Rolle</label>
|
<label for="newUserRole">Rolle</label>
|
||||||
<select id="newUserRole">
|
<select id="newUserRole">
|
||||||
|
|||||||
@@ -232,13 +232,12 @@ async function loadOrgUsers(orgId) {
|
|||||||
|
|
||||||
const tbody = document.getElementById("userTable");
|
const tbody = document.getElementById("userTable");
|
||||||
if (users.length === 0) {
|
if (users.length === 0) {
|
||||||
tbody.innerHTML = '<tr><td colspan="5" class="text-muted">Keine Nutzer</td></tr>';
|
tbody.innerHTML = '<tr><td colspan="4" class="text-muted">Keine Nutzer</td></tr>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tbody.innerHTML = users.map(u => `
|
tbody.innerHTML = users.map(u => `
|
||||||
<tr>
|
<tr>
|
||||||
<td>${esc(u.email)}</td>
|
<td>${esc(u.email)}</td>
|
||||||
<td>${esc(u.username)}</td>
|
|
||||||
<td>
|
<td>
|
||||||
<select class="btn btn-secondary btn-small" onchange="changeRole(${u.id}, this.value)" style="padding: 4px 8px;">
|
<select class="btn btn-secondary btn-small" onchange="changeRole(${u.id}, this.value)" style="padding: 4px 8px;">
|
||||||
<option value="member" ${u.role === "member" ? "selected" : ""}>Mitglied</option>
|
<option value="member" ${u.role === "member" ? "selected" : ""}>Mitglied</option>
|
||||||
@@ -426,7 +425,6 @@ function setupForms() {
|
|||||||
try {
|
try {
|
||||||
await API.post(`/api/users?org_id=${currentOrgId}`, {
|
await API.post(`/api/users?org_id=${currentOrgId}`, {
|
||||||
email: document.getElementById("newUserEmail").value,
|
email: document.getElementById("newUserEmail").value,
|
||||||
username: document.getElementById("newUserName").value,
|
|
||||||
role: document.getElementById("newUserRole").value,
|
role: document.getElementById("newUserRole").value,
|
||||||
});
|
});
|
||||||
closeModal("modalNewUser");
|
closeModal("modalNewUser");
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren