Untitled

Anonymous
plain_text
05/07/2026 2:44 AM
32.0 KB
8
Indexable
import tkinter as tk
from tkinter import ttk, messagebox
import mysql.connector


class Theme:
    BG        = "#FDFBD4"
    PRIMARY   = "#D4AF37"
    ACCENT    = "#CE8946"
    TEXT      = "#3b2f1c"
    BORDER    = "#8B6F47"


class Session:
    def __init__(self):
        self._user = None

    @property
    def user(self):
        return self._user

    @user.setter
    def user(self, value):
        self._user = value


session = Session()


class Model:
    def __init__(self):
        self.conn = mysql.connector.connect(
            host     = "localhost",
            user     = "root",
            password = "",
            database = "certifications"
        )
        self.cur = self.conn.cursor()

    def add_user(self, name, email, program, year):
        self.cur.execute("""
            INSERT INTO users (FullName, Email, Program, YearLevel)
            VALUES (%s,%s,%s,%s)
        """, (name, email, program, year))
        self.conn.commit()
        return self.cur.lastrowid

    def get_user(self, uid):
        self.cur.execute("SELECT * FROM users WHERE UserID=%s", (uid,))
        return self.cur.fetchone()

    def add_cert(self, name, cdate, exp, status, sid, uid):
        self.cur.execute("""
            INSERT INTO certifications
            (CertificationName, CertificationDate,
            ExpirationDate, RenewalStatus,
            SpecializationID, UserID)
            VALUES (%s,%s,%s,%s,%s,%s)
        """, (name, cdate, exp, status, sid, uid))
        self.conn.commit()

    def update_cert(self, cid, name, cdate, exp, status, sid):
        self.cur.execute("""
            UPDATE certifications
            SET CertificationName=%s,
                CertificationDate=%s,
                ExpirationDate=%s,
                RenewalStatus=%s,
                SpecializationID=%s
            WHERE CertificationID=%s
        """, (name, cdate, exp, status, sid, cid))
        self.conn.commit()

    def delete_cert(self, cid, uid):
        self.cur.execute("""
            DELETE FROM certifications
            WHERE CertificationID=%s
            AND UserID=%s
        """, (cid, uid))
        self.conn.commit()

    def get_my(self, uid):
        self.cur.execute("""
            SELECT CertificationID,
                   CertificationName,
                   CertificationDate,
                   ExpirationDate,
                   RenewalStatus,
                   SpecializationID,
                   UserID
            FROM certifications
            WHERE UserID=%s
        """, (uid,))
        return self.cur.fetchall()

    def get_all(self):
        self.cur.execute("""
            SELECT CertificationID,
                   CertificationName,
                   CertificationDate,
                   ExpirationDate,
                   RenewalStatus,
                   SpecializationID,
                   UserID
            FROM certifications
        """)
        return self.cur.fetchall()

    def get_by_specialization(self, sid):
        self.cur.execute("""
            SELECT CertificationID,
                   CertificationName,
                   CertificationDate,
                   ExpirationDate,
                   RenewalStatus,
                   SpecializationID,
                   UserID
            FROM certifications
            WHERE SpecializationID=%s
        """, (sid,))
        return self.cur.fetchall()

    def get_specializations_by_level(self, level):
        self.cur.execute("""
            SELECT SpecializationID, SpecializationName 
            FROM specializations 
            WHERE Level=%s 
            ORDER BY SpecializationName
        """, (level,))
        return self.cur.fetchall()

    def get_all_levels(self):
        self.cur.execute("SELECT DISTINCT Level FROM specializations ORDER BY Level")
        existing_levels = [row[0] for row in self.cur.fetchall()]
        all_levels      = ["Basic", "Intermediate", "Advanced"]
        return sorted(list(set(all_levels + existing_levels)))

    def get_all_specializations(self):
        self.cur.execute("SELECT SpecializationID, SpecializationName FROM specializations ORDER BY SpecializationName")
        return self.cur.fetchall()

    def get_specialization(self, sid):
        self.cur.execute("SELECT * FROM specializations WHERE SpecializationID=%s", (sid,))
        return self.cur.fetchone()


model = Model()


class BaseWindow:
    def __init__(self, root, title, size):
        self.root = root
        self.root.title(title)
        self.root.geometry(size)
        self.root.configure(bg = Theme.BG)
        self.root.resizable(False, False)

    def cert_frame(self, parent):
        outer = tk.Frame(parent, bg = Theme.BORDER, bd = 8)
        outer.place(relx = 0.5, rely = 0.5, anchor = "center", width = 750, height = 500)
        inner = tk.Frame(outer, bg = Theme.BG)
        inner.pack(expand = True, fill = "both", padx = 25, pady = 25)
        return inner

    def label(self, parent, text, size = 12, bold = False):
        tk.Label(
            parent,
            text = text,
            font  = ("Times New Roman", size, "bold" if bold else "normal"),
            bg    = Theme.BG,
            fg    = Theme.TEXT
        ).pack(pady = 4)

    def entry(self, parent):
        e = tk.Entry(
            parent,
            font      = ("Times New Roman", 13),
            width     = 28,
            bd        = 3,
            relief    = "groove",
            justify   = "center"
        )
        e.pack(pady = 4)
        return e

    def button(self, parent, text, cmd, width = 22, height = 1):
        tk.Button(
            parent,
            text    = text,
            font    = ("Times New Roman", 12, "bold"),
            bg      = Theme.PRIMARY,
            fg      = Theme.TEXT,
            width   = width,
            height  = height,
            bd      = 3,
            relief  = "raised",
            command = cmd
        ).pack(pady = 6)

    def exit_button(self, parent):
        btn_frame = tk.Frame(parent, bg = Theme.BG)
        btn_frame.pack(pady = 20)

        tk.Button(
            btn_frame,
            text    = "❌ EXIT",
            font    = ("Times New Roman", 11, "bold"),
            bg      = "#d32f2f",
            fg      = "white",
            width   = 12,
            height  = 1,
            bd      = 3,
            relief  = "raised",
            command = self.root.quit
        ).pack()

    def back_button(self, parent, back_cmd):
        btn_frame = tk.Frame(parent, bg = Theme.BG)
        btn_frame.pack(pady = 20)

        tk.Button(
            btn_frame,
            text    = "← BACK",
            font    = ("Times New Roman", 11, "bold"),
            bg      = Theme.ACCENT,
            fg      = Theme.TEXT,
            width   = 12,
            height  = 1,
            bd      = 3,
            relief  = "raised",
            command = back_cmd
        ).pack()


class StartPage(BaseWindow):
    def __init__(self, root):
        super().__init__(root, "CERTIFICATE ACCESS", "900x600")

        frame = self.cert_frame(root)

        tk.Label(
            frame,
            text = "CERTIFICATE OF ACCESS",
            font = ("Times New Roman", 30, "bold"),
            bg   = Theme.BG,
            fg   = Theme.ACCENT
        ).pack(pady = (40, 5))

        tk.Label(
            frame,
            text = "🏅 OFFICIAL SEAL",
            font = ("Times New Roman", 14, "bold"),
            bg   = Theme.BG,
            fg   = Theme.BORDER
        ).pack(pady = 10)

        tk.Label(
            frame,
            text = "This certifies that access is hereby granted\n"
                   "to use the Information Technology Certificate Management System",
            font     = ("Times New Roman", 13),
            bg       = Theme.BG,
            justify  = "center"
        ).pack(pady = 15)

        tk.Label(
            frame,
            text = "Select User Type:",
            bg   = Theme.BG,
            font = ("Times New Roman", 13, "bold")
        ).pack(pady = 10)

        self.button(frame, "NEW USER", self.new_user)
        self.button(frame, "OLD USER", self.old_user)

        self.exit_button(frame)

    def new_user(self):
        self.root.destroy()
        UserForm(tk.Tk(), True)

    def old_user(self):
        self.root.destroy()
        UserForm(tk.Tk(), False)


class UserForm(BaseWindow):
    def __init__(self, root, is_new):
        super().__init__(root, "USER FORM", "800x550")

        self.is_new = is_new

        frame = self.cert_frame(root)

        container = tk.Frame(frame, bg = Theme.BG)
        container.place(relx = 0.5, rely = 0.5, anchor = "center")

        if is_new:
            self.label(container, "Welcome, new user!", 20, True)
            self.label(container, "Full Name:", 14, True)
            self.name = self.entry(container)
            self.label(container, "Email:", 14, True)
            self.email = self.entry(container)
            self.label(container, "Program:", 14, True)
            self.program = self.entry(container)
            self.label(container, "Year Level:", 14, True)
            self.year = ttk.Combobox(container, values = ["1", "2", "3", "4"], width = 26, state = "readonly")
            self.year.pack(pady = 4)
        else:
            self.label(container, "Welcome back!", 20, True)
            self.label(container, "Enter User ID:", 14, True)
            self.uid = self.entry(container)

        tk.Frame(container, bg = Theme.BG, height = 20).pack()
        self.button(container, "CONFIRM", self.submit)

        self.back_button(container, self.go_back)

    def go_back(self):
        self.root.destroy()
        StartPage(tk.Tk())

    def submit(self):
        if self.is_new:
            uid = model.add_user(
                self.name.get(),
                self.email.get(),
                self.program.get(),
                self.year.get()
            )
            messagebox.showinfo("Success", f"Your User ID is: {uid}")
        else:
            session.user = model.get_user(self.uid.get())
            if session.user:
                self.root.destroy()
                Dashboard(tk.Tk())
            else:
                messagebox.showerror("Error", "User not found.")


class Dashboard(BaseWindow):
    def __init__(self, root):
        super().__init__(root, "DASHBOARD", "900x600")

        frame = self.cert_frame(root)

        container = tk.Frame(frame, bg = Theme.BG)
        container.place(relx = 0.5, rely = 0.5, anchor = "center")

        self.label(container, f"Welcome, {session.user[1]}!", 18, True)
        self.label(container, "Start managing your certificates now!", 13)

        self.button(container, "ADD Certificate", lambda: CertWindow(tk.Toplevel(self.root), "ADD"), width = 24)
        self.button(container, "UPDATE Certificate", lambda: CertWindow(tk.Toplevel(self.root), "UPDATE"), width = 24)
        self.button(container, "DELETE Certificate", lambda: CertWindow(tk.Toplevel(self.root), "DELETE"), width = 24)
        self.button(container, "VIEW My Certificates", lambda: CertWindow(tk.Toplevel(self.root), "MY"), width = 24)
        self.button(container, "VIEW Other Certificates", lambda: CertWindow(tk.Toplevel(self.root), "OTHER"), width = 24)
        self.button(container, "VIEW Specializations", lambda: SpecializationWindow(tk.Toplevel(self.root)), width = 24)

        self.back_button(container, self.go_back)

    def go_back(self):
        session.user = None
        self.root.destroy()
        StartPage(tk.Tk())


class CertWindow(BaseWindow):
    def __init__(self, root, mode):
        super().__init__(root, mode, "1350x720")
        self.mode = mode

        if mode in ["ADD", "UPDATE", "OTHER"]:
            self.dual_layout()
        else:
            self.center_layout()

    def dual_layout(self):
        main = tk.Frame(self.root, bg = Theme.BG)
        main.place(relx = 0.5, rely = 0.5, anchor = "center", relwidth = 0.97, relheight = 0.92)

        self.left = tk.Frame(main, bg = Theme.BG, width = 300)
        self.left.pack(side = "left", fill = "y", padx = (15, 10))
        self.left.pack_propagate(False)

        self.right = tk.Frame(main, bg = Theme.BG)
        self.right.pack(side = "right", expand = True, fill = "both", padx = (10, 15))

        if self.mode in ["ADD", "UPDATE"]:
            self.build_form()

        if self.mode == "OTHER":
            self.build_other_buttons()

        self.build_table(self.right)

    def center_layout(self):
        container = tk.Frame(self.root, bg = Theme.BG)
        container.place(relx = 0.5, rely = 0.5, anchor = "center", relheight = 0.92)

        title = "DELETE CERTIFICATIONS" if self.mode == "DELETE" else "VIEW MY CERTIFICATES"

        self.label(container, title, 18, True)

        table_holder = tk.Frame(container, bg = Theme.BORDER, bd = 5)
        table_holder.pack(pady = 15)

        inner = tk.Frame(table_holder, bg = Theme.BG)
        inner.pack(padx = 10, pady = 10)

        self.build_table(inner, small = True)

        if self.mode == "DELETE":
            tk.Button(
                container,
                text   = "DELETE SELECTED RECORD",
                font   = ("Times New Roman", 12, "bold"),
                bg     = Theme.PRIMARY,
                fg     = Theme.TEXT,
                width  = 32,
                height = 2,
                bd     = 3,
                command = self.delete
            ).pack(pady = 12)

    def go_back(self):
        self.root.destroy()
        Dashboard(tk.Tk())

    def build_form(self):
        wrapper = tk.Frame(self.left, bg = Theme.BG)
        wrapper.place(relx = 0.5, rely = 0.5, anchor = "center")

        self.label(wrapper, "ADD CERTIFICATION" if self.mode == "ADD" else "UPDATE CERTIFICATION", 18, True)
        self.label(wrapper, "Certification Name", 12, True)
        self.name = self.entry(wrapper)
        self.label(wrapper, "Certification Date", 12, True)
        self.date = self.entry(wrapper)
        self.label(wrapper, "Expiration Date", 12, True)
        self.exp = self.entry(wrapper)
        self.label(wrapper, "Renewal Status", 12, True)
        self.status = ttk.Combobox(wrapper, values = ["Active", "Expired"], width = 26, state = "readonly")
        self.status.pack(pady = 4)
        self.label(wrapper, "Specialization ID", 12, True)
        self.sid = ttk.Combobox(wrapper, width = 26, state = "readonly")
        self.sid.pack(pady = 4)
        self.refresh_specialization_dropdown()

        self.button(wrapper, "SAVE", self.save, width = 18)

    def refresh_specialization_dropdown(self):
        specs = model.get_all_specializations()
        spec_values = [f"{sid} ({name})" for sid, name in specs]
        if hasattr(self, 'sid'):
            self.sid['values'] = spec_values

    def build_table(self, parent, small = False):
        table_frame = tk.Frame(parent, bg = Theme.BORDER, bd = 5)
        table_frame.pack(fill = "both", expand = True, padx = 10, pady = 10)

        inner = tk.Frame(table_frame, bg = Theme.BG)
        inner.pack(fill = "both", expand = True)

        columns = ("CertificationID", "CertificationName", "CertificationDate", "ExpirationDate", "RenewalStatus", "SpecializationID", "UserID")

        self.tree = ttk.Treeview(inner, columns = columns, show = "headings", height = 11 if small else 14)

        headings = [
            "Certification ID",
            "Certification Name",
            "Certification Date",
            "Expiration Date",
            "Renewal Status",
            "Specialization ID",
            "User ID"
        ]
        widths = [90, 170, 120, 120, 110, 120, 70]

        for c, h, w in zip(columns, headings, widths):
            self.tree.heading(c, text = h)
            self.tree.column(c, width = w, anchor = "center")

        v_scroll = ttk.Scrollbar(inner, orient = "vertical", command = self.tree.yview)
        h_scroll = ttk.Scrollbar(inner, orient = "horizontal", command = self.tree.xview)

        self.tree.configure(yscrollcommand = v_scroll.set, xscrollcommand = h_scroll.set)

        self.tree.grid(row = 0, column = 0, sticky = "nsew")
        v_scroll.grid(row = 0, column = 1, sticky = "ns")
        h_scroll.grid(row = 1, column = 0, sticky = "ew")

        inner.grid_rowconfigure(0, weight = 1)
        inner.grid_columnconfigure(0, weight = 1)

        self.load()

    def load(self):
        self.tree.delete(*self.tree.get_children())

        if self.mode in ["ADD", "UPDATE", "DELETE", "MY"]:
            data = model.get_my(session.user[0])
        else:
            data = model.get_all()

        for row in data:
            self.tree.insert("", "end", values = row)

    def save(self):
        sid = self.sid.get().split()[0]

        if self.mode == "ADD":
            model.add_cert(self.name.get(), self.date.get(), self.exp.get(), self.status.get(), sid, session.user[0])
        else:
            item = self.tree.focus()
            if not item:
                return
            cid = self.tree.item(item)["values"][0]
            model.update_cert(cid, self.name.get(), self.date.get(), self.exp.get(), self.status.get(), sid)

        self.load()
        self.refresh_specialization_dropdown()

    def delete(self):
        item = self.tree.focus()
        if not item:
            return
        cid = self.tree.item(item)["values"][0]
        model.delete_cert(cid, session.user[0])
        self.load()

    def build_other_buttons(self):
        wrap = tk.Frame(self.left, bg = Theme.BG)
        wrap.place(relx = 0.5, rely = 0.5, anchor = "center")

        self.label(wrap, "All User Certifications", 16, True)

        buttons = [
            ("Networking", 1),
            ("Cybersecurity", 2),
            ("Software Development", 3),
            ("Data Analytics", 4),
            ("Cloud Computing", 5)
        ]

        for text, sid in buttons:
            self.button(wrap, text, lambda x = sid: self.filter_spec(x), width = 24)

        self.button(wrap, "Show All", self.show_all, width = 24)

    def filter_spec(self, sid):
        self.tree.delete(*self.tree.get_children())
        for row in model.get_by_specialization(sid):
            self.tree.insert("", "end", values = row)

    def show_all(self):
        self.tree.delete(*self.tree.get_children())
        for row in model.get_all():
            self.tree.insert("", "end", values = row)


class SpecializationWindow(BaseWindow):
    def __init__(self, root):
        super().__init__(root, "SPECIALIZATIONS", "1000x750")
        
        main = tk.Frame(self.root, bg = Theme.BG)
        main.place(relx = 0.5, rely = 0.5, anchor = "center", relwidth = 0.95, relheight = 0.92)

        left = tk.Frame(main, bg = Theme.BG, width = 450)
        left.pack(side = "left", fill = "both", padx = (20, 15), pady = (0, 20))
        left.pack_propagate(False)

        self.label(left, "SPECIALIZATION DESCRIPTIONS", 16, True)
    
        level_frame = tk.Frame(left, bg = Theme.BG)
        level_frame.pack(fill = "x", pady = (40, 20))
        
        level_label_frame = tk.Frame(level_frame, bg = Theme.BG)
        level_label_frame.pack(pady = (0, 10))
        self.label(level_label_frame, "SELECT LEVEL:", 14, True)
        
        btn_container = tk.Frame(level_frame, bg = Theme.BG)
        btn_container.pack()
      
        btn_advanced = tk.Button(
            btn_container,
            text    = "ADVANCED",
            font    = ("Times New Roman", 13, "bold"),
            bg      = Theme.PRIMARY,
            fg      = Theme.TEXT,
            width   = 12,
            height  = 2,
            bd      = 4,
            relief  = "raised",
            command = lambda: self.show_level("Advanced")
        )
        btn_advanced.pack(side = "left", padx = 15)
        
        btn_intermediate = tk.Button(
            btn_container,
            text    = "INTERMEDIATE",
            font    = ("Times New Roman", 13, "bold"),
            bg      = Theme.ACCENT,
            fg      = Theme.TEXT,
            width   = 14,
            height  = 2,
            bd      = 4,
            relief  = "raised",
            command = lambda: self.show_level("Intermediate")
        )
        btn_intermediate.pack(side = "left", padx = 15)

        desc_frame = tk.Frame(left, bg = Theme.BORDER, bd = 3, relief = "groove")
        desc_frame.pack(fill = "both", expand = True, pady = (20, 0))
        
        desc_title = tk.Label(
            desc_frame,
            text = "DESCRIPTION",
            font = ("Times New Roman", 14, "bold"),
            bg = Theme.BG,
            fg = Theme.PRIMARY
        )
        desc_title.pack(pady = 15)
        
        self.desc_text = tk.Text(
            desc_frame, 
            height = 12, 
            width = 50, 
            font = ("Times New Roman", 12), 
            wrap = "word",
            bg = "#f9f9f9",
            relief = "flat",
            bd = 2
        )
        self.desc_text.pack(padx = 20, pady = 10, fill = "both", expand = True)

        right = tk.Frame(main, bg = Theme.BG)
        right.pack(side = "right", expand = True, fill = "both", padx = (15, 20))

        self.build_spec_table(right)

        self.desc_text.insert("1.0", "Click 'ADVANCED' or 'INTERMEDIATE' button,\nthen select a specialization to view its description.")

    def go_back(self):
        self.root.destroy()
        Dashboard(tk.Tk())

    def build_spec_table(self, parent):
        table_frame = tk.Frame(parent, bg = Theme.BORDER, bd = 5)
        table_frame.pack(fill = "both", expand = True, padx = 5, pady = 5)

        inner = tk.Frame(table_frame, bg = Theme.BG)
        inner.pack(fill = "both", expand = True, padx = 15, pady = 15)

        columns = ("ID", "Specialization", "Level")
        self.spec_tree = ttk.Treeview(inner, columns = columns, show = "headings", height = 18)

        headings = ["ID", "Specialization Name", "Level"]
        widths = [80, 350, 120]

        for i, (c, h, w) in enumerate(zip(columns, headings, widths)):
            self.spec_tree.heading(c, text = h)
            self.spec_tree.column(c, width = w, anchor = "center")

        v_scroll = ttk.Scrollbar(inner, orient = "vertical", command = self.spec_tree.yview)
        self.spec_tree.configure(yscrollcommand = v_scroll.set)

        self.spec_tree.grid(row = 0, column = 0, sticky = "nsew")
        v_scroll.grid(row = 0, column = 1, sticky = "ns")

        inner.grid_rowconfigure(0, weight = 1)
        inner.grid_columnconfigure(0, weight = 1)

        self.spec_tree.bind("<<TreeviewSelect>>", self.on_spec_select)

    def show_level(self, level):
        self.spec_tree.delete(*self.spec_tree.get_children())
        self.desc_text.delete("1.0", "end")
        
        specs = model.get_specializations_by_level(level)
        for sid, name in specs:
            self.spec_tree.insert("", "end", values = (sid, name, level))
        
        self.desc_text.insert("1.0", f"No specialization selected.\nClick on a specialization to view its description.")

    def on_spec_select(self, event):
        item = self.spec_tree.selection()
        if item:
            selected_item = item[0]
            values = self.spec_tree.item(selected_item)["values"]
            sid = values[0]
            
            spec = model.get_specialization(sid)
            if spec:
                self.desc_text.delete("1.0", "end")
                name = spec[1]
                desc = spec[2] if spec[2] else "No description available."
                level = spec[3]
                self.desc_text.insert("1.0", f"Specialization: {name}\nLevel: {level}\n\nDescription:\n{desc}")


class MainMenu:
    def __init__(self):
        self.root = tk.Tk()
        StartPage(self.root)

    def mainloop(self):
        self.root.mainloop()


if __name__ == "__main__":
    app = MainMenu()
    app.mainloop()
Editor is loading...
Leave a Comment