04/23 Enhance app functionalities

This commit is contained in:
2026-04-23 16:54:24 -04:00
parent 64419a445a
commit f4eea48e4d
8 changed files with 427 additions and 45 deletions
+79
View File
@@ -39,6 +39,9 @@ class AdminUsersView(ttk.Frame):
ttk.Button(toolbar, text="✕ Delete",
style="Danger.TButton",
command=self._delete_selected).pack(side="right")
ttk.Button(toolbar, text="🔑 Reset Password",
style="Ghost.TButton",
command=self._reset_password).pack(side="right", padx=(0, 8))
# Treeview
cols = ("ID", "Username", "Full Name", "Role", "Active", "Created")
@@ -76,6 +79,82 @@ class AdminUsersView(ttk.Frame):
# ─── Dialogs ──────────────────────────────────────────────────────────────
def _reset_password(self):
"""
Generate a random temporary password for the selected user, set it in
the database, copy it to the clipboard, and log the action.
The admin must communicate the temporary password to the user out-of-band;
the user should change it immediately via Change Password.
"""
import random
import string
uid = self._get_selected_id()
if not uid:
show_error("Please select a user to reset.")
return
if uid == self.current_user["id"]:
show_error("You cannot reset your own password here.\nUse Change Password instead.")
return
vals = self.tree.item(uid, "values")
username = vals[1] if vals else str(uid)
# Confirm before proceeding
from tkinter import messagebox
if not messagebox.askyesno(
"Reset Password",
f"Generate a new temporary password for '{username}'?\n\n"
"The temporary password will be copied to your clipboard.",
icon="warning",
):
return
# Build a strong random password that meets the existing policy:
# 8+ chars, uppercase, digit, special character
alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
while True:
pwd = "".join(random.SystemRandom().choices(alphabet, k=16))
if (any(c.isupper() for c in pwd)
and any(c.isdigit() for c in pwd)
and any(c in "!@#$%^&*" for c in pwd)):
break
try:
from models import update_user, get_user_by_id, log_action
user_data = get_user_by_id(uid)
if not user_data:
show_error("User not found.")
return
update_user(
self.current_user["id"],
uid,
user_data["username"],
user_data["role"],
user_data["full_name"],
user_data["is_active"],
password=pwd,
)
log_action(
self.current_user["id"], "RESET_PASSWORD", "users", uid,
f"Admin reset password for user '{username}' (id={uid})."
)
logger.info(
f"Password reset for user id={uid} '{username}' "
f"by admin '{self.current_user['username']}'."
)
# Copy to clipboard
self.clipboard_clear()
self.clipboard_append(pwd)
show_info(
f"Temporary password for '{username}' has been set and "
f"copied to your clipboard:\n\n{pwd}\n\n"
"Please share it with the user securely.\n"
"The user should change it immediately after logging in."
)
except Exception as e:
show_error(f"Password reset failed:\n{e}")
def _open_add_dialog(self):
UserDialog(self, self.current_user, user_data=None,
on_save=self._load_users)