add endpoint and UI for users to update their own username
This commit is contained in:
parent
21d7acd7e5
commit
e153a76b77
4 changed files with 77 additions and 5 deletions
17
main.py
17
main.py
|
|
@ -226,6 +226,23 @@ async def change_own_password(request: Request):
|
|||
conn.close()
|
||||
return {"status": "ok"}
|
||||
|
||||
@app.put("/api/users/me/username", dependencies=[Depends(is_authenticated)])
|
||||
async def change_own_username(request: Request):
|
||||
data = await request.json()
|
||||
new_username = data.get("username")
|
||||
if not new_username:
|
||||
raise HTTPException(status_code=400, detail="New username required")
|
||||
user_id = request.session.get("user_id")
|
||||
try:
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
c.execute('UPDATE users SET username = ? WHERE id = ?', (new_username, user_id))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except sqlite3.IntegrityError:
|
||||
raise HTTPException(status_code=400, detail="Username already exists")
|
||||
return {"status": "ok"}
|
||||
|
||||
class InstanceCreate(BaseModel):
|
||||
name: str
|
||||
ip: str
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
const usersList = document.getElementById('users-list');
|
||||
const createUserForm = document.getElementById('create-user-form');
|
||||
const changePasswordForm = document.getElementById('change-password-form');
|
||||
const changeUsernameForm = document.getElementById('change-username-form');
|
||||
const profileSuccess = document.getElementById('profile-success');
|
||||
const helpBtn = document.getElementById('help-btn');
|
||||
const helpModal = document.getElementById('help-modal');
|
||||
|
|
@ -265,6 +266,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
} else {
|
||||
navAdmin.style.display = 'none';
|
||||
}
|
||||
document.getElementById('profile-username').value = currentUser.username;
|
||||
};
|
||||
|
||||
logoutBtn.addEventListener('click', async () => {
|
||||
|
|
@ -277,6 +279,28 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
}
|
||||
});
|
||||
|
||||
changeUsernameForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const username = document.getElementById('profile-username').value;
|
||||
try {
|
||||
const res = await fetch('/api/users/me/username', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ username })
|
||||
});
|
||||
if (res.ok) {
|
||||
currentUser.username = username;
|
||||
profileSuccess.style.display = 'block';
|
||||
setTimeout(() => profileSuccess.style.display = 'none', 3000);
|
||||
} else {
|
||||
const data = await res.json();
|
||||
alert(data.detail || 'Failed to update username');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error changing username', e);
|
||||
}
|
||||
});
|
||||
|
||||
createUserForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const username = document.getElementById('new-username').value;
|
||||
|
|
|
|||
|
|
@ -84,15 +84,26 @@
|
|||
<div id="profile-section" class="tab-content">
|
||||
<div class="card profile-card">
|
||||
<h2>My Profile</h2>
|
||||
<p class="helper-text">Change your account password below.</p>
|
||||
<form id="change-password-form">
|
||||
<p class="helper-text">Update your account details below.</p>
|
||||
|
||||
<form id="change-username-form" class="profile-form">
|
||||
<div class="form-group">
|
||||
<label for="profile-new-password">New Password</label>
|
||||
<label for="profile-username">Username</label>
|
||||
<input type="text" id="profile-username" placeholder="Enter new username" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Update Username</button>
|
||||
</form>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<form id="change-password-form" class="profile-form">
|
||||
<div class="form-group">
|
||||
<label for="profile-new-password">Password</label>
|
||||
<input type="password" id="profile-new-password" placeholder="Enter new password" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Update Password</button>
|
||||
</form>
|
||||
<div id="profile-success" class="success-msg" style="display: none;">Password updated successfully!</div>
|
||||
<div id="profile-success" class="success-msg" style="display: none;">Profile updated successfully!</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
|
|
|||
|
|
@ -197,8 +197,11 @@ input:focus {
|
|||
.btn-primary {
|
||||
background-color: var(--primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.login-card .btn-primary {
|
||||
width: 100%;
|
||||
margin-top: 0.5rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
|
|
@ -440,6 +443,23 @@ input:focus {
|
|||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.profile-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.25rem;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.profile-form .btn-primary {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background-color: var(--border-color);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.success-msg {
|
||||
color: var(--status-online);
|
||||
text-align: center;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue