From e46b845373a4df924962df0316f6343689bd7d19 Mon Sep 17 00:00:00 2001 From: Pranav J Date: Mon, 28 Oct 2024 18:37:36 +0530 Subject: [PATCH] Added password tags, fixed duplicate emails-password issue --- SRC/DataBase.py | 45 ++++++++++++++++++++++++++--------- SRC/Main.py | 63 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 93 insertions(+), 15 deletions(-) diff --git a/SRC/DataBase.py b/SRC/DataBase.py index d6a7c85..74c94c2 100644 --- a/SRC/DataBase.py +++ b/SRC/DataBase.py @@ -14,16 +14,19 @@ def create_table(self): website TEXT NOT NULL, email TEXT NOT NULL, username TEXT NOT NULL, - password TEXT NOT NULL + password TEXT NOT NULL, + category TEXT NOT NULL );''') except sqlite3.Error as e: raise DatabaseError(f"Database error: {e}") - def save_data(self, website, email, username, password): + def save_data(self, website, email, username, password, category): + if not all([website, email, username, password, category]): + raise ValueError("All fields must be filled.") try: with self.conn: - self.conn.execute("INSERT INTO passwords (website, email, username, password) VALUES (?, ?, ?, ?)", - (website, email, username, password)) + self.conn.execute("INSERT INTO passwords (website, email, username, password, category) VALUES (?, ?, ?, ?, ?)", + (website, email, username, password, category)) except sqlite3.Error as e: raise DatabaseError(f"Failed to save data: {e}") @@ -38,28 +41,48 @@ def get_all_passwords(self): raise DatabaseError(f"Failed to retrieve data: {e}") def update_password(self, old_data, new_data): + if not all(new_data.values()): + raise ValueError("All fields must be filled.") try: with self.conn: cursor = self.conn.cursor() cursor.execute( """ UPDATE passwords - SET website = ?, email = ?, username = ?, password = ? + SET website = ?, email = ?, username = ?, password = ?, category = ? WHERE website = ? AND email = ? AND username = ? AND password = ? """, - (new_data['website'], new_data['email'], new_data['username'], new_data['password'], - old_data[0], old_data[1], old_data[2], old_data[3]) + (new_data['website'], new_data['email'], new_data['username'], new_data['password'], new_data['category'], + old_data[0], old_data[1], old_data[2], old_data[3]) ) except sqlite3.Error as e: raise DatabaseError(f"Failed to update password: {e}") - def search_passwords(self, query): + def search_passwords(self, query, category=None): try: cursor = self.conn.cursor() - cursor.execute("SELECT website, email, username, password FROM passwords WHERE website LIKE ? OR email LIKE ?", - (f'%{query}%', f'%{query}%')) + if category: + cursor.execute("SELECT website, email, username, password FROM passwords WHERE (website LIKE ? OR email LIKE ?) AND category = ?", + (f'%{query}%', f'%{query}%', category)) + else: + cursor.execute("SELECT website, email, username, password FROM passwords WHERE website LIKE ? OR email LIKE ?", + (f'%{query}%', f'%{query}%')) + return cursor.fetchall() or [] + except sqlite3.Error as e: + raise DatabaseError(f"Failed to retrieve data: {e}") + + def search_passwords_by_categories(self, selected_categories): + try: + cursor = self.conn.cursor() + if not selected_categories: + return [] + + category_filter = " OR ".join(["category = ?"] * len(selected_categories)) + sql_query = f"SELECT website, email, username, password FROM passwords WHERE ({category_filter})" + + cursor.execute(sql_query, selected_categories) results = cursor.fetchall() - return results if results else [] + return results if results else [] except sqlite3.Error as e: raise DatabaseError(f"Failed to retrieve data: {e}") diff --git a/SRC/Main.py b/SRC/Main.py index 70cbf8c..da2e78c 100644 --- a/SRC/Main.py +++ b/SRC/Main.py @@ -151,6 +151,12 @@ def __init__(self): ) self.appearance_mode_optionemenu.grid(row=7, column=0, padx=20, pady=(10, 10)) + # Define categories + self.categories = ["Work", "Personal", "Entertainment", "Finance", "Health"] + + # Add category selection in the password entry form + self.category_vars = {category: ctk.BooleanVar() for category in self.categories} + self.content_frame = ctk.CTkFrame(self) self.content_frame.grid(row=0, column=1, sticky="nsew", padx=20, pady=20) self.content_frame.grid_columnconfigure(0, weight=1) @@ -210,6 +216,12 @@ def add_password_form(self, pw_data=None): button_frame = ctk.CTkFrame(form_frame) button_frame.pack(fill="x", pady=(20, 0)) + category_frame = ctk.CTkFrame(self.content_frame) + category_frame.pack(pady=(10, 0)) + + for category, var in self.category_vars.items(): + ctk.CTkCheckBox(category_frame, text=category, variable=var).pack(side="left", padx=5) + if pw_data is None: ctk.CTkButton( button_frame, text="Generate Password", command=self.generate_password @@ -272,10 +284,18 @@ def generate_password(self): def save_password(self): data = {key: widget.get() for key, widget in self.entrywid.items()} + + selected_categories = [cat for cat, var in self.category_vars.items() if var.get()] + + if not all(data.values()) or not selected_categories: + msgbox.showwarning("Missing Information", "All fields must be filled, and at least one category must be selected.") + return + + data['category'] = ', '.join(selected_categories) + if not all(data.values()): msgbox.showwarning("Missing Information", "All fields must be filled!") - elif not is_valid_email(data['email']): msgbox.showwarning("Invalid Email", "Invalid email format. Please enter a valid email address.") elif not is_valid_username(data['username']): @@ -283,6 +303,12 @@ def save_password(self): elif not is_valid_website_url(data['website']): msgbox.showwarning("Invalid Website URL", "Website URL should be in format https://www.[websitename].[websitedomain]") else: + existing_passwords = db.get_all_passwords() + for entry in existing_passwords: + if entry[1] == data['email']: + msgbox.showwarning("Duplicate Entry", "This email already exists for this website. Please edit existing email or add another email.") + return + strng = password_strength(data["password"]) for widget in self.content_frame.winfo_children(): @@ -382,6 +408,15 @@ def search_passwords(self): side="left" ) + self.categories = ['Work', 'Personal', 'Entertainment', 'Finance', 'Other'] + self.category_vars = {category: ctk.BooleanVar() for category in self.categories} + self.category_frame = ctk.CTkFrame(self.content_frame) + self.category_frame.pack(pady=(10, 20)) + + for category, var in self.category_vars.items(): + ctk.CTkCheckBox(self.category_frame, text=category, variable=var).pack(side="left") + + self.search_results_frame = ctk.CTkScrollableFrame(self.content_frame) self.search_results_frame.pack(expand=True, fill="both", padx=20, pady=(0, 20)) @@ -390,11 +425,17 @@ def search_passwords(self): def perform_search(self): query = self.search_entry.get() - if not query: - msgbox.showwarning("Warning", "Please Enter A Search Query!") + selected_categories = [category for category, var in self.category_vars.items() if var.get()] + + if not query and not selected_categories: + msgbox.showwarning("Warning", "Please enter a search query or select at least one category!") return - self.search_results = db.search_passwords(query) + if query: + self.search_results = db.search_passwords(query, selected_categories) + else: + self.search_results = db.search_passwords_by_categories(selected_categories) + self.current_page = 0 if not self.search_results: @@ -642,6 +683,15 @@ def edit_password(self, pw_data): def update_password(self, old_data): new_data = {key: widget.get() for key, widget in self.entrywid.items()} + # Get selected categories from checkboxes + selected_categories = [cat for cat, var in self.category_vars.items() if var.get()] + + if not all(new_data.values()) or not selected_categories: + msgbox.showwarning("Missing Information", "All fields must be filled, and at least one category must be selected.") + return + + new_data['category'] = ', '.join(selected_categories) + if not all(new_data.values()): msgbox.showwarning("Missing Information", "All fields must be filled!") @@ -653,6 +703,11 @@ def update_password(self, old_data): msgbox.showwarning("Invalid Website URL", "Website URL should be in format https://www.[websitename].[websitedomain]") else: + existing_passwords = db.get_all_passwords() + for entry in existing_passwords: + if entry[0] == new_data['website'] and entry[1] == new_data['email'] and entry != old_data: + msgbox.showwarning("Duplicate Entry", "This email already exists for this website. Please edit the existing entry or use a different email.") + return try: db.update_password(old_data, new_data) self.clear_entries()