Add profile management features
- Introduced profile update and password change functionalities in main.py. - Added new ProfileUpdate and PasswordChange schemas in user.py. - Updated base.html to include a profile link in the navigation and modified user chip for better accessibility. - Enhanced CSS for user chip links to improve UI interaction.
This commit is contained in:
111
app/main.py
111
app/main.py
@@ -16,7 +16,7 @@ from app.core.security import create_access_token, hash_password, verify_passwor
|
||||
from app.db.session import Base, engine, get_db
|
||||
from app.models.system import SendLog
|
||||
from app.models.user import User
|
||||
from app.schemas.user import UserCreate
|
||||
from app.schemas.user import PasswordChange, ProfileUpdate, UserCreate
|
||||
from app.services.auth import get_admin_user, get_current_user, get_optional_user, require_editor_or_admin
|
||||
from app.services.config_store import get_config, set_config
|
||||
from app.services.csrf import CSRF_COOKIE_NAME, ensure_csrf_cookie, generate_csrf_token, validate_csrf
|
||||
@@ -123,6 +123,8 @@ def _base_context(request: Request, user: User, db: Session) -> dict:
|
||||
active_nav = "dashboard"
|
||||
if path.startswith("/admin/users"):
|
||||
active_nav = "users"
|
||||
elif path.startswith("/profil"):
|
||||
active_nav = "profile"
|
||||
return {
|
||||
"user": user,
|
||||
"csrf_token": ensure_csrf_cookie(request),
|
||||
@@ -533,3 +535,110 @@ def create_user(
|
||||
db.add(user)
|
||||
db.commit()
|
||||
return RedirectResponse(url="/admin/users?created=1", status_code=status.HTTP_302_FOUND)
|
||||
|
||||
|
||||
def _profile_context(request: Request, user: User, db: Session, **extra) -> dict:
|
||||
context = _base_context(request, user, db)
|
||||
context.setdefault("error_message", None)
|
||||
context.setdefault("pw_error_message", None)
|
||||
context.setdefault("success_message", None)
|
||||
context.update(extra)
|
||||
return context
|
||||
|
||||
|
||||
@app.get("/profil", response_class=HTMLResponse)
|
||||
def profile_page(request: Request, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)):
|
||||
success = None
|
||||
if request.query_params.get("updated") == "1":
|
||||
success = "Profil wurde aktualisiert."
|
||||
elif request.query_params.get("pw") == "1":
|
||||
success = "Passwort wurde geändert."
|
||||
return _render(request, "profile.html", _profile_context(request, current_user, db, success_message=success))
|
||||
|
||||
|
||||
@app.post("/profil", response_class=HTMLResponse)
|
||||
def update_profile(
|
||||
request: Request,
|
||||
csrf_token: str = Form(...),
|
||||
email: str = Form(...),
|
||||
full_name: str = Form(...),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
try:
|
||||
validate_csrf(request, csrf_token)
|
||||
except HTTPException:
|
||||
return _render(
|
||||
request,
|
||||
"profile.html",
|
||||
_profile_context(request, current_user, db, error_message="Sitzung abgelaufen. Bitte Seite neu laden und erneut versuchen."),
|
||||
)
|
||||
|
||||
try:
|
||||
payload = ProfileUpdate(email=email.strip(), full_name=full_name.strip())
|
||||
except ValidationError as exc:
|
||||
return _render(
|
||||
request,
|
||||
"profile.html",
|
||||
_profile_context(request, current_user, db, error_message=_format_validation_error(exc)),
|
||||
)
|
||||
|
||||
clash = db.query(User).filter(User.email == payload.email, User.id != current_user.id).first()
|
||||
if clash:
|
||||
return _render(
|
||||
request,
|
||||
"profile.html",
|
||||
_profile_context(request, current_user, db, error_message="Diese E-Mail-Adresse wird bereits verwendet."),
|
||||
)
|
||||
|
||||
current_user.email = payload.email
|
||||
current_user.full_name = payload.full_name
|
||||
db.commit()
|
||||
return RedirectResponse(url="/profil?updated=1", status_code=status.HTTP_302_FOUND)
|
||||
|
||||
|
||||
@app.post("/profil/passwort", response_class=HTMLResponse)
|
||||
def change_password(
|
||||
request: Request,
|
||||
csrf_token: str = Form(...),
|
||||
current_password: str = Form(...),
|
||||
new_password: str = Form(...),
|
||||
confirm_password: str = Form(...),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
try:
|
||||
validate_csrf(request, csrf_token)
|
||||
except HTTPException:
|
||||
return _render(
|
||||
request,
|
||||
"profile.html",
|
||||
_profile_context(request, current_user, db, pw_error_message="Sitzung abgelaufen. Bitte Seite neu laden und erneut versuchen."),
|
||||
)
|
||||
|
||||
if not verify_password(current_password, current_user.password_hash):
|
||||
return _render(
|
||||
request,
|
||||
"profile.html",
|
||||
_profile_context(request, current_user, db, pw_error_message="Das aktuelle Passwort ist nicht korrekt."),
|
||||
)
|
||||
|
||||
if new_password != confirm_password:
|
||||
return _render(
|
||||
request,
|
||||
"profile.html",
|
||||
_profile_context(request, current_user, db, pw_error_message="Die neuen Passwörter stimmen nicht überein."),
|
||||
)
|
||||
|
||||
try:
|
||||
payload = PasswordChange(new_password=new_password)
|
||||
except ValidationError as exc:
|
||||
return _render(
|
||||
request,
|
||||
"profile.html",
|
||||
_profile_context(request, current_user, db, pw_error_message=_format_validation_error(exc)),
|
||||
)
|
||||
|
||||
current_user.password_hash = hash_password(payload.new_password)
|
||||
db.commit()
|
||||
return RedirectResponse(url="/profil?pw=1", status_code=status.HTTP_302_FOUND)
|
||||
|
||||
Reference in New Issue
Block a user