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()
|
conn.close()
|
||||||
return {"status": "ok"}
|
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):
|
class InstanceCreate(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
ip: str
|
ip: str
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
const usersList = document.getElementById('users-list');
|
const usersList = document.getElementById('users-list');
|
||||||
const createUserForm = document.getElementById('create-user-form');
|
const createUserForm = document.getElementById('create-user-form');
|
||||||
const changePasswordForm = document.getElementById('change-password-form');
|
const changePasswordForm = document.getElementById('change-password-form');
|
||||||
|
const changeUsernameForm = document.getElementById('change-username-form');
|
||||||
const profileSuccess = document.getElementById('profile-success');
|
const profileSuccess = document.getElementById('profile-success');
|
||||||
const helpBtn = document.getElementById('help-btn');
|
const helpBtn = document.getElementById('help-btn');
|
||||||
const helpModal = document.getElementById('help-modal');
|
const helpModal = document.getElementById('help-modal');
|
||||||
|
|
@ -265,6 +266,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
} else {
|
} else {
|
||||||
navAdmin.style.display = 'none';
|
navAdmin.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
document.getElementById('profile-username').value = currentUser.username;
|
||||||
};
|
};
|
||||||
|
|
||||||
logoutBtn.addEventListener('click', async () => {
|
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) => {
|
createUserForm.addEventListener('submit', async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const username = document.getElementById('new-username').value;
|
const username = document.getElementById('new-username').value;
|
||||||
|
|
|
||||||
|
|
@ -84,15 +84,26 @@
|
||||||
<div id="profile-section" class="tab-content">
|
<div id="profile-section" class="tab-content">
|
||||||
<div class="card profile-card">
|
<div class="card profile-card">
|
||||||
<h2>My Profile</h2>
|
<h2>My Profile</h2>
|
||||||
<p class="helper-text">Change your account password below.</p>
|
<p class="helper-text">Update your account details below.</p>
|
||||||
<form id="change-password-form">
|
|
||||||
|
<form id="change-username-form" class="profile-form">
|
||||||
<div class="form-group">
|
<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>
|
<input type="password" id="profile-new-password" placeholder="Enter new password" required>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">Update Password</button>
|
<button type="submit" class="btn btn-primary">Update Password</button>
|
||||||
</form>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
|
|
@ -197,8 +197,11 @@ input:focus {
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background-color: var(--primary);
|
background-color: var(--primary);
|
||||||
color: white;
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-card .btn-primary {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 0.5rem;
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary:hover {
|
.btn-primary:hover {
|
||||||
|
|
@ -440,6 +443,23 @@ input:focus {
|
||||||
color: var(--text-muted);
|
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 {
|
.success-msg {
|
||||||
color: var(--status-online);
|
color: var(--status-online);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue