From 4306cc5d5cb46b451fd1bcdab162a93c8d9e9169 Mon Sep 17 00:00:00 2001 From: Eren Date: Thu, 27 Feb 2025 17:53:12 +0100 Subject: [PATCH 1/4] ignore added --- .gitignore | 2 + task_1/task1.py | 88 +++ task_2_crm/python_files/PrefenceAdminMenu.py | 114 ++++ task_2_crm/python_files/PrefenceMenu.py | 102 ++++ .../PrefenceAdminMenu.cpython-313.pyc | Bin 0 -> 9559 bytes .../__pycache__/PrefenceMenu.cpython-313.pyc | Bin 0 -> 8101 bytes .../__pycache__/adminmenu.cpython-313.pyc | Bin 0 -> 6486 bytes .../applications_page.cpython-313.pyc | Bin 0 -> 23358 bytes .../__pycache__/interviews.cpython-313.pyc | Bin 0 -> 23073 bytes .../__pycache__/loginscreen.cpython-313.pyc | Bin 0 -> 9451 bytes .../__pycache__/loginsecreen.cpython-313.pyc | Bin 0 -> 7930 bytes .../__pycache__/main.cpython-313.pyc | Bin 0 -> 1286 bytes .../mentor_interview.cpython-313.pyc | Bin 0 -> 18628 bytes .../__pycache__/state.cpython-313.pyc | Bin 0 -> 393 bytes task_2_crm/python_files/adminmenu.py | 107 ++++ task_2_crm/python_files/applications_page.py | 525 ++++++++++++++++++ task_2_crm/python_files/events.json | 14 + task_2_crm/python_files/fetching.py | 94 ++++ task_2_crm/python_files/interviews.py | 246 ++++++++ task_2_crm/python_files/loginscreen.py | 121 ++++ task_2_crm/python_files/mentor_interview.py | 235 ++++++++ task_2_crm/python_files/role.json | 3 + 22 files changed, 1651 insertions(+) create mode 100644 .gitignore create mode 100644 task_1/task1.py create mode 100644 task_2_crm/python_files/PrefenceAdminMenu.py create mode 100644 task_2_crm/python_files/PrefenceMenu.py create mode 100644 task_2_crm/python_files/__pycache__/PrefenceAdminMenu.cpython-313.pyc create mode 100644 task_2_crm/python_files/__pycache__/PrefenceMenu.cpython-313.pyc create mode 100644 task_2_crm/python_files/__pycache__/adminmenu.cpython-313.pyc create mode 100644 task_2_crm/python_files/__pycache__/applications_page.cpython-313.pyc create mode 100644 task_2_crm/python_files/__pycache__/interviews.cpython-313.pyc create mode 100644 task_2_crm/python_files/__pycache__/loginscreen.cpython-313.pyc create mode 100644 task_2_crm/python_files/__pycache__/loginsecreen.cpython-313.pyc create mode 100644 task_2_crm/python_files/__pycache__/main.cpython-313.pyc create mode 100644 task_2_crm/python_files/__pycache__/mentor_interview.cpython-313.pyc create mode 100644 task_2_crm/python_files/__pycache__/state.cpython-313.pyc create mode 100644 task_2_crm/python_files/adminmenu.py create mode 100644 task_2_crm/python_files/applications_page.py create mode 100644 task_2_crm/python_files/events.json create mode 100644 task_2_crm/python_files/fetching.py create mode 100644 task_2_crm/python_files/interviews.py create mode 100644 task_2_crm/python_files/loginscreen.py create mode 100644 task_2_crm/python_files/mentor_interview.py create mode 100644 task_2_crm/python_files/role.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..edcbc6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +task_2_crm/python_files/credentials.json +task_2_crm/python_files/token.json diff --git a/task_1/task1.py b/task_1/task1.py new file mode 100644 index 0000000..981503a --- /dev/null +++ b/task_1/task1.py @@ -0,0 +1,88 @@ +import psycopg2 + +try: + con = psycopg2.connect( + dbname = "postgres", + user = "postgres", + password = "sunset2014", + host = "localhost", + port = "5432" + ) + cur = con.cursor() + cur.execute(''' + create table if not exists employees_table( + emp_id bigint primary key, + first_name varchar(50), + last_name varchar(50), + salary integer, + job_title varchar(50), + gender varchar(10), + hire_date date + ) + ''') + rows = [ + (17679, 'Robert', 'Gilmore', 110000, 'Operations Director', 'Male', '2018-09-04'), + (26650, 'Elvis', 'Ritter', 86000, 'Sales Manager', 'Male', '2017-11-24'), + (30840, 'David', 'Barrow', 85000, 'Data Scientist', 'Male', '2019-12-02'), + (49714, 'Hugo', 'Forester', 55000, 'IT Support Specialist', 'Male', '2019-11-22'), + (51821, 'Linda', 'Foster', 95000, 'Data Scientist', 'Female', '2019-04-29'), + (67323, 'Lisa', 'Wiener', 75000, 'Business Analyst', 'Female', '2018-08-09'), + (70950, 'Rodney', 'Weaver', 87000, 'Project Manager', 'Male', '2018-12-20'), + (71329, 'Gayle', 'Meyer', 77000, 'HR Manager', 'Female', '2019-06-28'), + (76589, 'Jason', 'Christian', 99000, 'Project Manager', 'Male', '2019-01-21'), + (97927, 'Billie', 'Lanning', 67000, 'Web Developer', 'Female', '2018-06-25') + ] + cur.executemany(""" + INSERT INTO employees_table (emp_id, first_name, last_name, salary, job_title, gender, hire_date) + VALUES (%s, %s, %s, %s, %s, %s, %s) + ON CONFLICT (emp_id) DO NOTHING; + """, rows) + + cur.execute(''' + CREATE TABLE IF NOT EXISTS departments_table ( + emp_id BIGINT, + dept_name VARCHAR(50), + dept_id INTEGER, + PRIMARY KEY (emp_id, dept_id) + ) + ''') + rows2 = [ + (17679, 'Operations', 13), + (26650, 'Marketing', 14), + (30840, 'Operations', 13), + (49823, 'Technology', 12), + (51821, 'Operations', 13), + (67323, 'Marketing', 14), + (71119, 'Administrative', 11), + (76589, 'Operations', 13), + (97927, 'Technology', 12) + ] + cur.executemany(""" + INSERT INTO departments_table (emp_id, dept_name, dept_id) + VALUES (%s, %s, %s) + ON CONFLICT (emp_id, dept_id) DO NOTHING; + """, rows2) + con.commit() +except Exception as e: + print(f"connection failed:{e}") + +# sorgular + +print("________________question1_______________") +query_1 = "select * from employees_table where salary > (select salary from employees_table where first_name = 'Rodney' and last_name = 'Weaver')" +cur.execute(query_1) +question1 = cur.fetchall() +print(question1) +print("________________question2_______________") +query_2 = "select (min(salary)+max(salary))/2 from employees_table" +cur.execute(query_2) +question2 = cur.fetchall() +print(question2) +print("________________question3_______________") + + + + + + +cur.close() \ No newline at end of file diff --git a/task_2_crm/python_files/PrefenceAdminMenu.py b/task_2_crm/python_files/PrefenceAdminMenu.py new file mode 100644 index 0000000..390092f --- /dev/null +++ b/task_2_crm/python_files/PrefenceAdminMenu.py @@ -0,0 +1,114 @@ +# Form implementation generated from reading ui file 'PrefenceAdminMenu.ui' +# +# Created by: PyQt6 UI code generator 6.8.0 +# +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets +import subprocess + +class Ui_Form_Admin(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.setEnabled(True) + Form.resize(670, 524) + self.gridLayout = QtWidgets.QGridLayout(Form) + self.gridLayout.setObjectName("gridLayout") + self.pushButton_Applications = QtWidgets.QPushButton(parent=Form) + self.pushButton_Applications.setObjectName("pushButton_Applications") + self.gridLayout.addWidget(self.pushButton_Applications, 2, 1, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.gridLayout.addItem(spacerItem, 0, 0, 1, 1) + self.pushButton_Interviews = QtWidgets.QPushButton(parent=Form) + self.pushButton_Interviews.setObjectName("pushButton_Interviews") + self.gridLayout.addWidget(self.pushButton_Interviews, 4, 1, 1, 1) + self.pushButton_Exit = QtWidgets.QPushButton(parent=Form) + self.pushButton_Exit.setEnabled(True) + self.pushButton_Exit.setObjectName("pushButton_Exit") + self.gridLayout.addWidget(self.pushButton_Exit, 6, 2, 1, 1) + self.pushButton_Mentor_Meeting = QtWidgets.QPushButton(parent=Form) + self.pushButton_Mentor_Meeting.setEnabled(True) + self.pushButton_Mentor_Meeting.setObjectName("pushButton_Mentor_Meeting") + self.gridLayout.addWidget(self.pushButton_Mentor_Meeting, 3, 1, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.gridLayout.addItem(spacerItem1, 6, 1, 1, 1) + self.pushButton_Main_Menu = QtWidgets.QPushButton(parent=Form) + self.pushButton_Main_Menu.setObjectName("pushButton_Main_Menu") + self.gridLayout.addWidget(self.pushButton_Main_Menu, 6, 0, 1, 1) + self.title = QtWidgets.QLabel(parent=Form) + font = QtGui.QFont() + font.setPointSize(14) + font.setBold(False) + font.setItalic(False) + font.setWeight(50) + font.setStrikeOut(False) + self.title.setFont(font) + self.title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.title.setObjectName("title") + self.gridLayout.addWidget(self.title, 1, 0, 1, 3) + self.pushButton = QtWidgets.QPushButton(parent=Form) + self.pushButton.setEnabled(True) + self.pushButton.setObjectName("pushButton") + self.gridLayout.addWidget(self.pushButton, 5, 1, 1, 1) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + self.pushButton_Applications.clicked.connect(self.open_applications) + self.pushButton_Mentor_Meeting.clicked.connect(self.open_mentormeeting) + self.pushButton_Interviews.clicked.connect(self.open_interviews) + self.pushButton.clicked.connect(self.open_adminmenu) + self.pushButton_Main_Menu.clicked.connect(self.open_mainmenu) + self.pushButton_Exit.clicked.connect(self.exit) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.pushButton_Applications.setText(_translate("Form", "APPLICATIONS")) + self.pushButton_Interviews.setText(_translate("Form", "INTERWIEWS")) + self.pushButton_Exit.setText(_translate("Form", "EXIT")) + self.pushButton_Mentor_Meeting.setText(_translate("Form", "MENTOR MEETING")) + self.pushButton_Main_Menu.setText(_translate("Form", "MAIN MENU")) + self.title.setText(_translate("Form", "PREFENCE ADMIN MENU")) + self.pushButton.setText(_translate("Form", "ADMIN MENU")) + + + def open_applications(self): + appPath = r"task_2_crm\python_files\applications_page.py" + subprocess.Popen(["python", appPath]) + QtWidgets.QApplication.instance().quit() + + def open_mentormeeting(self): + MentorPath = r'task_2_crm\python_files\mentor_interview.py' + subprocess.Popen(["python", MentorPath]) + QtWidgets.QApplication.instance().quit() + + def open_interviews(self): + interviewsPath = r'task_2_crm\python_files\interviews.py' + subprocess.Popen(["python", interviewsPath]) + QtWidgets.QApplication.instance().quit() + + def open_adminmenu(self): + adminPath = r"task_2_crm\python_files\adminmenu.py" + subprocess.Popen(["python", adminPath]) + QtWidgets.QApplication.instance().quit() + + def open_mainmenu(self): + loginPath = r"task_2_crm\python_files\loginscreen.py" + subprocess.Popen(["python", loginPath]) + QtWidgets.QApplication.instance().quit() + + def exit(self): + QtWidgets.QApplication.instance().quit() + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + Form = QtWidgets.QWidget() + ui = Ui_Form_Admin() + ui.setupUi(Form) + Form.show() + sys.exit(app.exec()) \ No newline at end of file diff --git a/task_2_crm/python_files/PrefenceMenu.py b/task_2_crm/python_files/PrefenceMenu.py new file mode 100644 index 0000000..0a052b3 --- /dev/null +++ b/task_2_crm/python_files/PrefenceMenu.py @@ -0,0 +1,102 @@ +# Form implementation generated from reading ui file 'PrefenceMenu.ui' +# +# Created by: PyQt6 UI code generator 6.8.0 +# +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets +import subprocess + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.setEnabled(True) + Form.resize(670, 496) + self.gridLayout = QtWidgets.QGridLayout(Form) + self.gridLayout.setObjectName("gridLayout") + self.pushButton_Mentor_Meeting = QtWidgets.QPushButton(parent=Form) + self.pushButton_Mentor_Meeting.setObjectName("pushButton_Mentor_Meeting") + self.gridLayout.addWidget(self.pushButton_Mentor_Meeting, 3, 1, 1, 1) + self.pushButton_Interviews = QtWidgets.QPushButton(parent=Form) + self.pushButton_Interviews.setObjectName("pushButton_Interviews") + self.gridLayout.addWidget(self.pushButton_Interviews, 4, 1, 1, 1) + self.pushButton_Exit = QtWidgets.QPushButton(parent=Form) + self.pushButton_Exit.setEnabled(True) + self.pushButton_Exit.setObjectName("pushButton_Exit") + self.gridLayout.addWidget(self.pushButton_Exit, 5, 2, 1, 1) + self.pushButton_Main_Menu = QtWidgets.QPushButton(parent=Form) + self.pushButton_Main_Menu.setObjectName("pushButton_Main_Menu") + self.gridLayout.addWidget(self.pushButton_Main_Menu, 5, 0, 1, 1) + self.title = QtWidgets.QLabel(parent=Form) + font = QtGui.QFont() + font.setPointSize(14) + font.setBold(False) + font.setItalic(False) + font.setWeight(50) + font.setStrikeOut(False) + self.title.setFont(font) + self.title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.title.setObjectName("title") + self.gridLayout.addWidget(self.title, 1, 0, 1, 3) + self.pushButton_Applications = QtWidgets.QPushButton(parent=Form) + self.pushButton_Applications.setObjectName("pushButton_Applications") + self.gridLayout.addWidget(self.pushButton_Applications, 2, 1, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.gridLayout.addItem(spacerItem, 5, 1, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.gridLayout.addItem(spacerItem1, 0, 0, 1, 1) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + self.pushButton_Applications.clicked.connect(self.open_applications) + self.pushButton_Mentor_Meeting.clicked.connect(self.open_mentormeeting) + self.pushButton_Interviews.clicked.connect(self.open_interviews) + self.pushButton_Main_Menu.clicked.connect(self.open_mainmenu) + self.pushButton_Exit.clicked.connect(self.exit) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.pushButton_Mentor_Meeting.setText(_translate("Form", "MENTOR MEETING")) + self.pushButton_Interviews.setText(_translate("Form", "INTERWIEWS")) + self.pushButton_Exit.setText(_translate("Form", "EXIT")) + self.pushButton_Main_Menu.setText(_translate("Form", "MAIN MENU")) + self.title.setText(_translate("Form", "PREFENCE MENU")) + self.pushButton_Applications.setText(_translate("Form", "APPLICATIONS")) + + def open_applications(self): + appPath = r'task_2_crm\python_files\applications_page.py' + subprocess.Popen(["python", appPath]) + Form.close() + + def open_mentormeeting(self): + MentorPath = r'task_2_crm\python_files\mentor_interview.py' + subprocess.Popen(["python", MentorPath]) + Form.close() + + def open_interviews(self): + interviewsPath = r'task_2_crm\python_files\interviews.py' + subprocess.Popen(["python", interviewsPath]) + Form.close() + + def open_mainmenu(self): + loginPath = r"task_2_crm\python_files\loginscreen.py" + subprocess.Popen(["python", loginPath]) + Form.close() + + def exit(self): + Form.close() + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + Form = QtWidgets.QWidget() + ui = Ui_Form() + ui.setupUi(Form) + Form.show() + sys.exit(app.exec()) \ No newline at end of file diff --git a/task_2_crm/python_files/__pycache__/PrefenceAdminMenu.cpython-313.pyc b/task_2_crm/python_files/__pycache__/PrefenceAdminMenu.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e129febddd6cf6e3330fea63dd491de05fcc02d GIT binary patch literal 9559 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 literal 0 HcmV?d00001 diff --git a/task_2_crm/python_files/__pycache__/adminmenu.cpython-313.pyc b/task_2_crm/python_files/__pycache__/adminmenu.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7dfaeb52530859457c8c582c4e8529ff1402c736 GIT binary patch literal 6486 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

8G+jf)tb-M=+!E1n9Y(qrIy9}MFYQ< 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 literal 0 HcmV?d00001 diff --git a/task_2_crm/python_files/__pycache__/loginscreen.cpython-313.pyc b/task_2_crm/python_files/__pycache__/loginscreen.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..02b2787ee111cea040a169da48131ec2e2edcccd GIT binary patch literal 9451 zcmd@)ZEPDycC+M?Tz*N^w=B!j>LW5~N0MbrPAtdnIkNmA+d7LIo!v-x%$i(L8&OMU zmW(9@McvQXO$+;a2u^^1SOo%9DGJmEii1(ykG8h|7NSLi&PD|SG)3WmZtQ~(`PKJk zxg;giv3p2>0v*}2GjHC!c{B6o&3kY7#P9bIOwE56|EQUe|6r9u<|urhbaI4zN+cq2 zrwBE_9OYQuMs4u5owASdlpk|Y$C#5k$6VAkCQxC_P2FQ2>KXG=uZaEZr+j06>StyC zRMl8Dt%fr9K|pe}5LzQSA+K#FokViA5J{MJ4B1T{Xx((ZhHv6XDwR;9a#~GlhIitOtZL^}Etb4!xF=4lnlc(w(*Qr4(P!Vzq|<=poH#9C zP!a(A$=k_=)AC|6lQvuv=hRqSLDVyfuFG)++CrRRn@B_Mm^hZy($O-;h!ZNfWKaGL zGT1UsBU8opu&r1u7Q)sh7a@d95^G|?0yG9a`$;#Ma#?7Tu<4Rr;t$wuMB}Ce3m!Jb z$*Qt%Cz<3dikfZGrrRV3{tXrQ5rJ|Cd7TtTgH4>ViKLx~@E3O+vbU2NF67Mg1G!U~ zL_*f?-iqG6C0Br+@EU7Qb`rTVvOxDEYT!!{7ogW$QpVSqq_bXJ< zBK=1deJ-6$^~crpZ015Fnn-F&|JlX#Y*OnzlZ<5&O7A&EnR}x@n*30qX(bk!fg$vM zb6hp5CS=<8z79La(Qh4@^i1!YpL2$wXwhU$)#BqJr(sL#2A`7CvxZYyQ1vv_k|{+q zc-D+2Gn4Fe%+(J(hy3T-Ed_RTQl+wP<*dfk+0|gto#!)$m_G3E3s`RYUU9_=eYi^^GfUTs?f{@N!?? z8_Ie^536e~yT5k(FKf%u)#LZwgSYvO>bk3of3dh+|H&U-<{wtqJ#!GxP~JTV|Gw3| zKnQRebO#*D4~-C&pwLb znJTE+B^!fsMd&sLwIfsq(di~$6dgX~$SeTJ^Aiw~grbRaWzr+ZK!iS2#Ctc?8LBKQ zV*Jjps8WssVy1~SnYi<7?ar^o*qvW#3hncZ-o2sFay0QmCXvzPd3i~f#c`0QBC6pw z2L!P(oGBSd$%bQ5NzbX{A&xD6h&Ke>3h1sFLQ2;4i%A+Y9Bg|Go_%4pP(j*hzeWC(xfnF|(4jYfpv&@-x`0X@XiGG(Jb|lVp&S zY%Sz{f%1|a^tMCdA$KxO?vk8Tm?Vcd>h2~Xm*G8)B4}#BN62xsxa&|UDy?gvMhLZ6cY%qr}p8W5P&9g$bAet5@k8t}B(T(p0@w3O8D%(l-pZ_tsR#8Hx@|5^q6) z3ph(=0xnP$Y)RqvEdZ!abyzS^;ZAEsEt+igE6u0N>Q(wy9M zXO&CeAAJ8RjA?NPr=jxx73CCo-c#b$Duwr1rP6n*+bV|#ty1Y5-d`$Pr4kn}7^RYw zcwgG<aIQd`d(+c!Ul**)|)`G%JJFVHlOpjXS()Sglqf)O*v#PU3WwWZ(>(!;>ScyZc zw2AtwOGgDhN|fRxR6oAtW9Ex!+Ar!guwB&GAzN}!7A&`6!*PVFa^jH>m|3bD)zV-g zf(J)M%eH&;Ew+rMudXgBfW8+1OYXA;V{v%XfF%=>G5rY5U-=kt>p>IJN@bp>_|c{o#JC_w=i)S( z(PF*PWFiS1b`3=@yg3v-C>H7$XVtXw9HRq!kkjHES#=ZfKiE_&V`6v~y{%VcWiTo$ zgVBSVNWGYFih|>;#9oo~;DOlS;CGQW$RjiXm%N3Api1mu293!(AK$$-clXx48{flX z#|{kb8=Uz+vDncA`}XYpVHR7C?me(~=(`p>)NMHQOiH1K5Q%`3pN>R~DqTsN2k{*> z4Gyyp>c`XtB__eyptuu8RaDW^R8B-Ln!%F*pp2LxGn_)v`Zk;iGsuDzjwIB$Hjg;y zx*Gms{a8Yd8(vmL5(=g0TNqUd4Aw9=jCpP@!%2@rsALK(Sc&0{UolHVF|7 za3f14OGi-ju?!!J1Vk>F5hqs^B2;rq%y31Mnx;h4hHqBZVhJU}&Uf7-$wl9z8gx##REh}tW?poG!Lf2C#Y42HyU7x?q=Y;L7 zbw^g%u^h{{4P@H}a>Cw?#*UTleCJTMb7;MB|7HF!y?}Mqd&Qd<#H=8GR-5k_$aW0m zI}T+#4&{WyNb$9msr9yj5=k6BFLY&vuFpnSci!B)-n~C3yiugHWyG)BcCPZ*lUuv@ zWre=A{-Zfzl(A{j3}uDTYFAF^+X8#&JO9*fb9=xIcl%9lw~X?G@wqcA?EHIoJ~*5W z4(Ed-+2BY{I9kTu_dkyv!By9K>mFRNZEPUi;Jkp0tlD$J>sw%tZ61H%soe*w(+aDT z7fkeytk97c*n)QFcOA^`I+zpQg07oauRq(?pA+`L>a}&RynX#$9MqJtmaNc{7do>- z=VwE!O*cE&yM}VYem1t*6wC_2)g6^KeowY-Pfi#BqOChuK3df7aX~L|OGp z+*Vr;A&lE%Fu>wx3%7wEj$4q3R}2(MWll`I>O125Rc3tu=6$++_gSM(=$|w$a++Tcrv^vfkiUD)cq35=%n<~ZlJN$eiEK3 zD22Pe=$ME}3X5QdojXDSiq5#fr_m&F=xM5^C^|?i%xu&|GtgNp3qKo<6uiEqDV|Tm zt7vg^Px_#NYed~2Ymjwuxzqs+KKz8g}4X(EyS`)T`C9@WIZDn@l z-PNVr!P_lsRcHbHm$&u4xAkFD{PKy7YH{WGdiCy&!1jD#=luZK4y)?gf%kF&`C*_w zALz*jdUAo_SIzA!uC=D%HGZRE+j4MautfYdd0$)B*OvG7WPLqrJ5N0D zoqW~=<2`5?{`Og*P|z`&_pb+=Myu?1Ynw*f?f0rYqphxc?VizI*QT2awJp1;zJ>z6 zOv0lv8RIk#v^yHfELk@Xge8i1)+ASY$OSlW;esYA2GK1TAz`%Nx1`FqSjow+++OJc zz~YZ-;bO4AG+e1YZV&Mp47{;(Eh=*qA1yUmT!dF7&_r-H=9NB*)-t^0`X|-MF*rIA zhK(=CHD~cCz(HV;Gm4g>Gk|M4I6iisz`bEF%C?Nk&PgUUse(N|o4iQJk*v);GT67^8T*`s>=OA;Vc$k;*Y%UkVEdxB{TKaUR=dzbab0m;t-eyd z%;%d!+2&AA*u{(>(?Dy>3T-(-L_E(G&tLhTH(mZe3Is;Q${(=7pNy)r@QU{`0dW-s zg#Ea{5)CF58jv)l!pl^sDHK#i@cWp}VOA~>*khAG$N(^cFA|8YiurG_yCoaJjqRP+ z4=@Y(i`s3!2vv}cV757!6GBWjOp6zto1D?me<9nlfYFg8fv z#OwrSY=S8);YAVhV2A*nYX}i|B9VFak`HBHB=SKhM$f}tfN5$2&% zye8PGpll@?z>7`8B^HgyX}AEv&QQRyHT(r1H>xBOkqA8Bo`r5YTp#2|=52$fDa8!m zJ#-8Z|Mt(xZ)_8sW6w7;wpPa&_swCKqv2UCWRD4C>`bs8$oxF~Mg-_?XE!9Rh3 zo;HryxQ1)HpA!5&9^(n`yS%h+-}Z&4@tXe2g`Y31d&Em4U-+9p`RS!&4|&hWr~c^F hpPqThyFNbg$0sgJSI=KL|H-=#_~yrM!nZIs{|CdOfbakS literal 0 HcmV?d00001 diff --git a/task_2_crm/python_files/__pycache__/loginsecreen.cpython-313.pyc b/task_2_crm/python_files/__pycache__/loginsecreen.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6f1e3e192d5114d13b4de5ad9ef2a04aaefc467 GIT binary patch literal 7930 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 literal 0 HcmV?d00001 diff --git a/task_2_crm/python_files/__pycache__/main.cpython-313.pyc b/task_2_crm/python_files/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a29fc5c1dc4350f6fbfd1f1ad2d63ed8ba98dd50 GIT binary patch literal 1286 zcmZ`&-D?zA6hC)%W_Ob88m&pNyR~jZs2ymdLKi`-hzWw0*e260LPsx?$#or_on7y} zD+FKmNh(wnB;ccOk~jP4v;Tm>it*x`55>2%n_?b&?w#Ew3Lcnq&pjXaoZmTTdZp4R zAU(bGxKXeG-s;PM@_nKAD++7igHL{h^MsT07PqQ!0H(pW%HZb$Qp;t&JQw7qq1F%N zcHp3o9ptAWuxlh!*D#N!Dl{A~|4xgZr3#BbEnj1iRHNH9~2WghEg%ba1t+jzlMdx?o%cjI)#m^GsZqt#&ZCv=Fpc z<<(Y7ufz!xK{Jfg+4d?Q!#Fj$8_Mh;T>(vE64_1{-ngYZg$?(>Uv7DGs{FfscdUm7 zh=w)eWr+AJUe@5^-bA|?s>9N5&%SmEd+;&U$zTvTVr)9vy&Ny%p-Kikjjo1igRLl= zHDl>nyrgZ;%`oY(tP52>u2my~$*f;$>H~a3y~Zvo$hxpORrzCV(=EPo%NuU_m3wHz zJ@m+V>3+@kq5Xrw>LHuKmQh&4!7btWG0kM9uM<QIxL&H%-?WG&38jc<4>}t>r%kuH{@)GL z?~AXH?c9df6JI`*FD7QX3;)@cQ~B4moWt*3;#9T(S%yUib`B#mGs2au#?Kxz9*a0# zVb|m8?$K4x&7Zj76;$!()kRsGU6gYz&bS_ifo1X!)})#Jn96DMIF-tZSJolRXtu*W znKkSb{|3YLV8nOGwsM4!zv0_$yGSbck8cAW|9k=a4nEk^ExiWkdH%?spFLT4aqP@X Im^07)581LHBme*a literal 0 HcmV?d00001 diff --git a/task_2_crm/python_files/__pycache__/mentor_interview.cpython-313.pyc b/task_2_crm/python_files/__pycache__/mentor_interview.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa6c2019b39bbadd9bad20bdd6a57ff184ebb526 GIT binary patch literal 18628 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 literal 0 HcmV?d00001 diff --git a/task_2_crm/python_files/__pycache__/state.cpython-313.pyc b/task_2_crm/python_files/__pycache__/state.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d11d2c82c8e34625ffbb4ebf7e96e0e0c2d4079 GIT binary patch literal 393 zcmYLF%}T>S5S~dIOl%@nJbCiqB^U85;zhk_4~Cvx2qmto7@N483cW~th&)5dD@6|l zUqH+YI1`#WFyDSN^UV+22EjIveX6B;r}vwK-f&IYeIgY^@Cp$gfX2uov=oH)IO#>K zWp0zVEjY#k7zik+*3&mxiT>%}H`9CPr!_q?WT-TuSp?WVyJwy%G7M zc+6(;!&54a=(>;dMdKM+#9gF$$$;E!5tOj 1: + if identifier not in duplicate_entries: + # Kişiyi ve başvuru sayısını kaydedelim + entry["Tekrar Sayısı"] = identifier_counts[identifier] + duplicate_entries[identifier] = entry # Her kişiyi yalnızca bir kez ekle + + if not duplicate_entries: # Eğer hiç duplicate yoksa + QMessageBox.warning(self, "Warning", "No one found with multiple submissions.") + return + + # MessageBox'a yazılacak mesajı hazırlayalım + duplicate_info = f"Found {len(duplicate_entries)} users with multiple submissions:/n/n" + + for identifier, entry in duplicate_entries.items(): + name = entry.get("Adınız Soyadınız") + email = entry.get("Mail adresiniz") + repeat_count = entry.get("Tekrar Sayısı") + + # None veya boş veri kontrolü yapalım + if name and email: # Name ve email boş değilse + duplicate_info += f"- {name} ({email}) submitted {repeat_count} times./n" + + # None veya eksik değer olanları dışarıda bırakıyoruz + if duplicate_info.strip(): # Eğer mesaj boş değilse + QMessageBox.information(self, "Multiple Submissions Found", duplicate_info) + + # Debug için count bilgilerini yazdırıyoruz + print("Duplicate count per identifier:") + for identifier, count in identifier_counts.items(): + if count > 1: + print(f"{identifier}: {count} times") + + except Exception as e: + print(f"Error in filter_applications_function: {e}") + + + def previous_vit_check_function(self): + try: + # JSON dosyasını oku + file_path = r"coverted_files/Basvurular.json" # Dosyanın yolu + try: + with open(file_path, "r", encoding="utf-8") as file: + self.all_data = json.load(file) # JSON verisini yükle + except FileNotFoundError: + QMessageBox.critical(self, "Error", f"File '{file_path}' not found!") + return + except json.JSONDecodeError: + QMessageBox.critical(self, "Error", f"Invalid JSON format in '{file_path}'!") + return + + # JSON verisi boş mu? + if not self.all_data: + print("No JSON data loaded.") + QMessageBox.warning(self, "Warning", "No student records matching the filtered criteria were found!") + return + + # VIT3 harici kişileri bul + vit_data = [entry for entry in self.all_data if "VIT3" not in str(entry.values())] + + if not vit_data: # Eğer hiç VIT3 harici kişi yoksa + QMessageBox.warning(self, "Warning", "No student records matching the filtered criteria were found!") + return + + # Filtrelenen verileri tabloya yazdır + print(f"Found {len(vit_data)} records excluding VIT3.") + self.display_data(vit_data) + + except Exception as e: + print(f"Error in previous_vit_check_function: {e}") + + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = ApplicationsPage() + window.setWindowTitle("Applications") + window.setWindowIcon(QIcon("app_icon.png")) + window.resize(800, 600) + window.show() + sys.exit(app.exec()) \ No newline at end of file diff --git a/task_2_crm/python_files/events.json b/task_2_crm/python_files/events.json new file mode 100644 index 0000000..f0e7d37 --- /dev/null +++ b/task_2_crm/python_files/events.json @@ -0,0 +1,14 @@ +[ + { + "event_name": "Mezunlar Piknigi", + "start_time": "05.06.2025", + "attendees": "msevinc@gmail.com, ramazan1@example.com", + "organizer": "yavuz@werhere.com" + }, + { + "event_name": "It Sektorundeki Kadinlar Ilham Semineri", + "start_time": "12.03.2025", + "attendees": "erennecatikrc@example.com, hanife7@example.com", + "organizer": "ibrahim@werhere.com" + } +] diff --git a/task_2_crm/python_files/fetching.py b/task_2_crm/python_files/fetching.py new file mode 100644 index 0000000..c601e56 --- /dev/null +++ b/task_2_crm/python_files/fetching.py @@ -0,0 +1,94 @@ +from google.oauth2.credentials import Credentials +from google_auth_oauthlib.flow import InstalledAppFlow +from googleapiclient.discovery import build +from googleapiclient.http import MediaIoBaseDownload +import io, os +import pandas as pd +import psycopg2 + +SCOPES = ['https://www.googleapis.com/auth/drive.readonly'] +CLIENT_SECRETS_FILE = r'task_2_crm\python_files\credentials.json' +TOKEN_FILE = r'task_2_crm\python_files\token.json' + +if os.path.exists(TOKEN_FILE): + creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES) +else: + flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES) + creds = flow.run_local_server(port=0) + with open(TOKEN_FILE, 'w') as token: + token.write(creds.to_json()) + +service = build('drive', 'v3', credentials=creds) +folder_id = '1LFAU6uVOLzYatC5J_moXNOaNVL5SNGIt' +results = service.files().list(q=f"'{folder_id}' in parents", fields="files(id, name)").execute() +files = results.get('files', []) +excelDicts = {} + +for file in files: + file_id = file['id'] + file_name = file['name'].split('.')[0] + request = service.files().get_media(fileId=file_id) + fh = io.BytesIO() + downloader = MediaIoBaseDownload(fh, request) + done = False + while not done: + status, done = downloader.next_chunk() + fh.seek(0) + df = pd.read_excel(fh) + + df = df.astype(str).replace({'NaT': None, 'nan': None}) + + + excelDicts[file_name] = df + +conn = psycopg2.connect( + dbname="CRM", + user="postgres", + password="sunset2014", + host="localhost", + port="5432" +) +cur = conn.cursor() + +for table_name, df in excelDicts.items(): + try: + columns_with_types = ', '.join([f'"{col}" TEXT' for col in df.columns.tolist()]) + create_table_query = f'CREATE TABLE IF NOT EXISTS {table_name} ({columns_with_types});' + cur.execute(create_table_query) + + columns = [f'"{col}"' for col in df.columns.tolist()] + for _, row in df.iterrows(): + values = tuple(row) + placeholders = ', '.join(['%s'] * len(columns)) + query = f'INSERT INTO {table_name} ({", ".join(columns)}) VALUES ({placeholders})' + cur.execute(query, values) + + conn.commit() + except Exception as e: + print("Hata oluştu:", e) + conn.rollback() + +basvurularTable = """ + ALTER TABLE Basvurular ADD COLUMN id SERIAL PRIMARY KEY; + ALTER TABLE Mentor ADD COLUMN id SERIAL PRIMARY KEY; + ALTER TABLE Mulakatlar ADD COLUMN id SERIAL PRIMARY KEY; +""" +cur.execute(basvurularTable) + +cur.execute('ALTER TABLE Mentor ADD COLUMN basvuru_id INT;') +cur.execute(""" + ALTER TABLE Mentor + ADD CONSTRAINT fk_basvuru FOREIGN KEY (basvuru_id) + REFERENCES Basvurular(id) ON DELETE CASCADE; +""") + +cur.execute('ALTER TABLE Mulakatlar ADD COLUMN basvuru_id INT;') +cur.execute(""" + ALTER TABLE Mulakatlar + ADD CONSTRAINT fk_mulakat FOREIGN KEY (basvuru_id) + REFERENCES Basvurular(id) ON DELETE CASCADE; +""") + +conn.commit() +cur.close() +conn.close() diff --git a/task_2_crm/python_files/interviews.py b/task_2_crm/python_files/interviews.py new file mode 100644 index 0000000..574e9b7 --- /dev/null +++ b/task_2_crm/python_files/interviews.py @@ -0,0 +1,246 @@ +from PyQt6 import QtCore, QtWidgets +from PyQt6.QtWidgets import QCompleter, QTableWidgetItem +import json,sys +from PrefenceAdminMenu import Ui_Form_Admin +from PrefenceMenu import Ui_Form + + + + + +class Ui_interviewsWindow(object): + + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(854, 569) + self.centralwidget = QtWidgets.QWidget(parent=MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget) + self.gridLayout_2.setObjectName("gridLayout_2") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.columnView = QtWidgets.QTableWidget(parent=self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.columnView.sizePolicy().hasHeightForWidth()) + self.columnView.setSizePolicy(sizePolicy) + self.columnView.setLineWidth(0) + self.columnView.setMidLineWidth(0) + self.columnView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.columnView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.columnView.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents) + self.columnView.setIconSize(QtCore.QSize(0, 150)) + self.columnView.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerItem) + self.columnView.setGridStyle(QtCore.Qt.PenStyle.NoPen) + self.columnView.setCornerButtonEnabled(True) + self.columnView.setColumnCount(3) + self.columnView.setObjectName("columnView") + self.columnView.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.columnView.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.columnView.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.columnView.setHorizontalHeaderItem(2, item) + self.horizontalLayout.addWidget(self.columnView) + self.gridLayout_2.addLayout(self.horizontalLayout, 1, 0, 1, 1) + self.gridLayout = QtWidgets.QGridLayout() + self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetDefaultConstraint) + self.gridLayout.setContentsMargins(50, -1, 10, 10) + self.gridLayout.setHorizontalSpacing(7) + self.gridLayout.setObjectName("gridLayout") + self.pushButton_exit = QtWidgets.QPushButton(parent=self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pushButton_exit.sizePolicy().hasHeightForWidth()) + self.pushButton_exit.setSizePolicy(sizePolicy) + self.pushButton_exit.setObjectName("pushButton_exit") + self.gridLayout.addWidget(self.pushButton_exit, 5, 0, 1, 1, QtCore.Qt.AlignmentFlag.AlignHCenter|QtCore.Qt.AlignmentFlag.AlignVCenter) + self.pushButton_project_sended = QtWidgets.QPushButton(parent=self.centralwidget) + self.pushButton_project_sended.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pushButton_project_sended.sizePolicy().hasHeightForWidth()) + self.pushButton_project_sended.setSizePolicy(sizePolicy) + self.pushButton_project_sended.setObjectName("pushButton_project_sended") + self.gridLayout.addWidget(self.pushButton_project_sended, 4, 0, 1, 1) + self.label = QtWidgets.QLabel(parent=self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 2, 1, 1, QtCore.Qt.AlignmentFlag.AlignHCenter) + self.pushButton_search = QtWidgets.QPushButton(parent=self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pushButton_search.sizePolicy().hasHeightForWidth()) + self.pushButton_search.setSizePolicy(sizePolicy) + self.pushButton_search.setMinimumSize(QtCore.QSize(93, 28)) + self.pushButton_search.setObjectName("pushButton_search") + self.gridLayout.addWidget(self.pushButton_search, 3, 0, 1, 1, QtCore.Qt.AlignmentFlag.AlignHCenter) + self.pushButton_project_in = QtWidgets.QPushButton(parent=self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pushButton_project_in.sizePolicy().hasHeightForWidth()) + self.pushButton_project_in.setSizePolicy(sizePolicy) + self.pushButton_project_in.setObjectName("pushButton_project_in") + self.gridLayout.addWidget(self.pushButton_project_in, 4, 3, 1, 1, QtCore.Qt.AlignmentFlag.AlignHCenter) + self.pushButton_prefence = QtWidgets.QPushButton(parent=self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pushButton_prefence.sizePolicy().hasHeightForWidth()) + self.pushButton_prefence.setSizePolicy(sizePolicy) + self.pushButton_prefence.setObjectName("pushButton_prefence") + self.gridLayout.addWidget(self.pushButton_prefence, 5, 3, 1, 1, QtCore.Qt.AlignmentFlag.AlignHCenter) + self.lineEdit_input = QtWidgets.QLineEdit(parent=self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEdit_input.sizePolicy().hasHeightForWidth()) + self.lineEdit_input.setSizePolicy(sizePolicy) + self.lineEdit_input.setMinimumSize(QtCore.QSize(0, 0)) + self.lineEdit_input.setSizeIncrement(QtCore.QSize(0, 0)) + self.lineEdit_input.setObjectName("lineEdit_input") + self.gridLayout.addWidget(self.lineEdit_input, 3, 2, 1, 1) + self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(parent=MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 854, 26)) + self.menubar.setObjectName("menubar") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(parent=MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.columnView.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.Stretch) + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + item = self.columnView.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "Name Surname")) + item = self.columnView.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "Project Submission Date")) + item = self.columnView.horizontalHeaderItem(2) + item.setText(_translate("MainWindow", "Project Development Date")) + self.pushButton_exit.setText(_translate("MainWindow", "EXIT")) + self.pushButton_project_sended.setText(_translate("MainWindow", "Projects Sent")) + self.label.setText(_translate("MainWindow", "INTERVIEWS")) + self.pushButton_search.setText(_translate("MainWindow", "SEARCH")) + self.pushButton_project_in.setText(_translate("MainWindow", "Projects Received")) + self.pushButton_prefence.setText(_translate("MainWindow", "Preferences")) + self.lineEdit_input.setPlaceholderText(_translate("MainWindow", "Enter text to search..")) + + + #calling methods + self.setup_completer() + self.pushButton_search.clicked.connect(self.search_data) + self.pushButton_project_sended.clicked.connect(self.sended) + self.pushButton_project_in.clicked.connect(self.arrived) + self.pushButton_exit.clicked.connect(self.exit) + self.pushButton_prefence.clicked.connect(self.preference) + + def jsonData(self): + jsonPath = r'coverted_files\Mulakatlar.json' + with open(jsonPath, 'r', encoding='utf-8') as file: + data = json.load(file) + return data + + def roleJson(self): + jsonPath = r"python_files\role.json" + with open(jsonPath, 'r', encoding="utf-8") as file: + data = json.load(file) + return data + + + def setup_completer(self): + data = self.jsonData() + names = [entry["Adınız Soyadınız"] for entry in data] + completer = QCompleter(names) + completer.setCaseSensitivity(QtCore.Qt.CaseSensitivity.CaseInsensitive) + self.lineEdit_input.setCompleter(completer) + + def search_data(self): + data = self.jsonData() + search_name = self.lineEdit_input.text().lower() + if not search_name: + return + found = False + for entry in data: + if search_name in entry["Adınız Soyadınız"].lower(): + self.update_table(entry) + found = True + break + if not found: + self.clear_table() + + def update_table(self, entry): + self.columnView.setRowCount(1) + self.columnView.setItem(0, 0, QTableWidgetItem(entry["Adınız Soyadınız"])) + self.columnView.setItem(0, 1, QTableWidgetItem(entry["Proje gonderilis tarihi"])) + self.columnView.setItem(0, 2, QTableWidgetItem(entry["Projenin gelis tarihi"])) + + + def clear_table(self): + self.columnView.setRowCount(0) + + + def sended(self): + jsonData = self.jsonData() + sendedItem = [item for item in jsonData if item["Proje gonderilis tarihi"]] + self.columnView.setRowCount(len(sendedItem)) + for i,j in enumerate(sendedItem): + self.columnView.setItem(i, 0, QTableWidgetItem(str(j.get("Adınız Soyadınız")))) + self.columnView.setItem(i, 1, QTableWidgetItem(str(j.get("Proje gonderilis tarihi")))) + self.columnView.setItem(i, 2, QTableWidgetItem(str(j.get("Projenin gelis tarihi")))) + + def arrived(self): + jsonData = self.jsonData() + arrivedItem = [item for item in jsonData if item['Projenin gelis tarihi']] + self.columnView.setRowCount(len(arrivedItem)) + for i,j in enumerate(arrivedItem): + self.columnView.setItem(i, 0, QTableWidgetItem(str(j.get("Adınız Soyadınız")))) + self.columnView.setItem(i, 1, QTableWidgetItem(str(j.get("Proje gonderilis tarihi")))) + self.columnView.setItem(i, 2, QTableWidgetItem(str(j.get("Projenin gelis tarihi")))) + + def exit(self): + QtWidgets.QApplication.quit() + + def preference(self): + state = self.roleJson() + if state["login"] == "admin": + self.userWindow = QtWidgets.QWidget() + self.user_ui = Ui_Form_Admin() + self.user_ui.setupUi(self.userWindow) + self.userWindow.show() + MainWindow.close() + elif state["login"] == "user": + self.adminWindow = QtWidgets.QWidget() + self.adminUi = Ui_Form() + self.adminUi.setupUi(self.adminWindow) + self.adminWindow.show() + MainWindow.close() + else: + print("calismadi") + + + +if __name__ == "__main__": + app = QtWidgets.QApplication(sys.argv) + MainWindow = QtWidgets.QMainWindow() + ui = Ui_interviewsWindow() + ui.setupUi(MainWindow) + MainWindow.show() + sys.exit(app.exec()) diff --git a/task_2_crm/python_files/loginscreen.py b/task_2_crm/python_files/loginscreen.py new file mode 100644 index 0000000..ba1d027 --- /dev/null +++ b/task_2_crm/python_files/loginscreen.py @@ -0,0 +1,121 @@ +import psycopg2 +import sys +from PyQt6.QtWidgets import ( + QApplication, QMainWindow, QLineEdit, QPushButton, QLabel, QVBoxLayout, QWidget, QMessageBox +) +from PyQt6.QtCore import Qt +from PyQt6.QtGui import QFont + +# PostgreSQL bağlantı ayarları +DB_CONFIG = { + "dbname": "CRM", + "user": "postgres", + "password": "sunset2014", + "host": "localhost", + "port": "5432" +} + +# Global değişken +current_user_role = None + +def get_user_role(username, password): + """Veritabanından kullanıcı bilgilerini al ve rolünü döndür.""" + try: + conn = psycopg2.connect(**DB_CONFIG) # Veritabanına bağlan + cur = conn.cursor() + + # Kullanıcı adı ve şifreyi kontrol eden SQL sorgusu + cur.execute("SELECT yetki FROM kullanicilar WHERE kullanici = %s AND parola = %s", (username, password)) + user_role = cur.fetchone() + + cur.close() + conn.close() + + return user_role[0] if user_role else None # Eğer kullanıcı varsa rolünü döndür + except Exception as e: + print(f"Veritabanı hatası: {e}") + return None + +class LoginWindow(QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle("Giriş Penceresi") + self.setFixedSize(400, 300) + + # Ana widget ve layout + self.central_widget = QWidget(self) + self.setCentralWidget(self.central_widget) + self.layout = QVBoxLayout(self.central_widget) + self.layout.setAlignment(Qt.AlignmentFlag.AlignCenter) + + # Kullanıcı adı giriş alanı + self.label_username = QLabel("Kullanıcı Adı:") + self.label_username.setFont(QFont("Arial", 12)) + self.layout.addWidget(self.label_username) + + self.input_username = QLineEdit(self) + self.input_username.setPlaceholderText("Kullanıcı adınızı girin") + self.layout.addWidget(self.input_username) + + # Şifre giriş alanı + self.label_password = QLabel("Şifre:") + self.label_password.setFont(QFont("Arial", 12)) + self.layout.addWidget(self.label_password) + + self.input_password = QLineEdit(self) + self.input_password.setEchoMode(QLineEdit.EchoMode.Password) + self.input_password.setPlaceholderText("Şifrenizi girin") + self.layout.addWidget(self.input_password) + + # Giriş butonu + self.login_button = QPushButton("Giriş Yap") + self.login_button.clicked.connect(self.handle_login) + self.layout.addWidget(self.login_button) + + # Uyarı mesajı + self.warning_label = QLabel("") + self.warning_label.setFont(QFont("Arial", 10)) + self.warning_label.setStyleSheet("color: red;") + self.layout.addWidget(self.warning_label) + + def handle_login(self): + """Giriş yapıldığında çağrılır.""" + username = self.input_username.text().strip() + password = self.input_password.text().strip() + + global current_user_role + current_user_role = get_user_role(username, password) + + if current_user_role: + if current_user_role == "admin": + QMessageBox.information(self, "Başarılı", "Hoşgeldiniz! Admin girişi yaptınız.") + self.redirect_to_admin() + else: + QMessageBox.information(self, "Başarılı", "Hoşgeldiniz! Kullanıcı girişi yaptınız.") + self.redirect_to_user_preferences() + else: + self.warning_label.setText("Kullanıcı adı veya şifre hatalı!") + + def redirect_to_admin(self): + """Admin ekranına yönlendirme.""" + from PrefenceAdminMenu import Ui_Form_Admin + self.admin_window = QWidget() + self.ui = Ui_Form_Admin() + self.ui.setupUi(self.admin_window) + self.admin_window.show() + self.close() + + def redirect_to_user_preferences(self): + """Kullanıcı tercihler ekranına yönlendirme.""" + from PrefenceMenu import Ui_Form + self.user_window = QWidget() + self.ui = Ui_Form() + self.ui.setupUi(self.user_window) + self.user_window.show() + self.close() + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = LoginWindow() + window.show() + sys.exit(app.exec()) diff --git a/task_2_crm/python_files/mentor_interview.py b/task_2_crm/python_files/mentor_interview.py new file mode 100644 index 0000000..c505b33 --- /dev/null +++ b/task_2_crm/python_files/mentor_interview.py @@ -0,0 +1,235 @@ +from PyQt6 import QtCore, QtGui, QtWidgets +from PyQt6.QtWidgets import QCompleter, QTableWidgetItem +import json,sys, psycopg2 +from psycopg2.extras import DictCursor +from PrefenceAdminMenu import Ui_Form_Admin +from PrefenceMenu import Ui_Form + + + +class Ui_mentorInterviewsWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(798, 637) + + self.centralwidget = QtWidgets.QWidget(parent=MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) + self.gridLayout.setObjectName("gridLayout") + self.comboBox = QtWidgets.QComboBox(parent=self.centralwidget) + self.comboBox.setObjectName("comboBox") + self.gridLayout.addWidget(self.comboBox, 3, 4, 1, 1) + self.pushButton_4 = QtWidgets.QPushButton(parent=self.centralwidget) + self.pushButton_4.setObjectName("pushButton_4") + self.gridLayout.addWidget(self.pushButton_4, 4, 1, 1, 1) + self.tableWidget = QtWidgets.QTableWidget(parent=self.centralwidget) + self.tableWidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.tableWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.tableWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents) + self.tableWidget.setShowGrid(True) + self.tableWidget.setGridStyle(QtCore.Qt.PenStyle.NoPen) + self.tableWidget.setWordWrap(True) + self.tableWidget.setCornerButtonEnabled(True) + self.tableWidget.setRowCount(0) + self.tableWidget.setColumnCount(5) + self.tableWidget.setObjectName("tableWidget") + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(2, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(3, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(4, item) + self.tableWidget.horizontalHeader().setCascadingSectionResizes(False) + self.tableWidget.verticalHeader().setCascadingSectionResizes(False) + self.tableWidget.verticalHeader().setHighlightSections(True) + self.gridLayout.addWidget(self.tableWidget, 5, 0, 1, 5) + self.pushButton = QtWidgets.QPushButton(parent=self.centralwidget) + self.pushButton.setObjectName("pushButton") + self.gridLayout.addWidget(self.pushButton, 2, 0, 1, 1) + self.pushButton_3 = QtWidgets.QPushButton(parent=self.centralwidget) + self.pushButton_3.setObjectName("pushButton_3") + self.gridLayout.addWidget(self.pushButton_3, 4, 0, 1, 1) + self.lineEdit = QtWidgets.QLineEdit(parent=self.centralwidget) + self.lineEdit.setAutoFillBackground(True) + self.lineEdit.setInputMask("") + self.lineEdit.setText("") + self.lineEdit.setFrame(True) + self.lineEdit.setEchoMode(QtWidgets.QLineEdit.EchoMode.Normal) + self.lineEdit.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.lineEdit.setDragEnabled(False) + self.lineEdit.setReadOnly(False) + self.lineEdit.setClearButtonEnabled(False) + self.lineEdit.setObjectName("lineEdit") + self.gridLayout.addWidget(self.lineEdit, 2, 4, 1, 1) + self.label = QtWidgets.QLabel(parent=self.centralwidget) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 3, 1, 1) + self.pushButton_2 = QtWidgets.QPushButton(parent=self.centralwidget) + self.pushButton_2.setObjectName("pushButton_2") + self.gridLayout.addWidget(self.pushButton_2, 2, 3, 1, 1) + MainWindow.setCentralWidget(self.centralwidget) + self.statusbar = QtWidgets.QStatusBar(parent=MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.tableWidget.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.Stretch) + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + self.pushButton_4.setText(_translate("MainWindow", "EXIT")) + item = self.tableWidget.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "Gorusme Tarihi")) + item = self.tableWidget.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "Isim Soyisim")) + item = self.tableWidget.horizontalHeaderItem(2) + item.setText(_translate("MainWindow", "Mentor")) + item = self.tableWidget.horizontalHeaderItem(3) + item.setText(_translate("MainWindow", "IT Bilgisi")) + item = self.tableWidget.horizontalHeaderItem(4) + item.setText(_translate("MainWindow", "Dil Seviyesi")) + self.pushButton.setText(_translate("MainWindow", "View All Interviews")) + self.pushButton_3.setText(_translate("MainWindow", "PREFERENCE")) + self.lineEdit.setPlaceholderText(_translate("MainWindow", "Enter the text to search")) + self.label.setText(_translate("MainWindow", "MENTOR MENU")) + self.pushButton_2.setText(_translate("MainWindow", "SEARCH")) + + #calling methods + self.sqlData() + self.setup_completer() + self.pushButton_2.clicked.connect(self.search_data) + self.comboBoxFilter() + self.comboBox.addItems(self.comboBoxFilter()) + self.comboBox.currentTextChanged.connect(self.showCombo) + self.pushButton.clicked.connect(self.showAll) + self.pushButton_4.clicked.connect(self.exit) + self.adminPreference = Ui_Form_Admin() + self.userPreference = Ui_Form() + self.pushButton_3.clicked.connect(self.preference) + + def sqlData(self): + con = psycopg2.connect( + dbname="CRM", + user="postgres", + password="sunset2014", + host="localhost", + port="5432" + ) + cur = con.cursor(cursor_factory=psycopg2.extras.DictCursor) + cur.execute('SELECT "Tarih", "Donem", "Aday Ismi", "Mentor", "Degerlendirme", "dil seviyesi", "id", "basvuru_id" FROM "mentor"') + data = cur.fetchall() + return data + + + + def roleJson(self): + jsonPath = r"task_2_crm\python_files\role.json" + with open(jsonPath, 'r', encoding="utf-8") as file: + data = json.load(file) + return data + + + def setup_completer(self): + data = self.sqlData() + names = [entry["Aday Ismi"] for entry in data] + completer = QCompleter(names) + completer.setCaseSensitivity(QtCore.Qt.CaseSensitivity.CaseInsensitive) + self.lineEdit.setCompleter(completer) + + def search_data(self): + data = self.sqlData() + search_name = self.lineEdit.text().lower() + if not search_name: + return + found = False + for entry in data: + if search_name in entry["Aday Ismi"].lower(): + self.update_table(entry) + found = True + break + if not found: + self.clear_table() + + def update_table(self, entry): + self.tableWidget.setRowCount(1) + self.tableWidget.setItem(0, 0, QTableWidgetItem(entry["Tarih"])) + self.tableWidget.setItem(0, 1, QTableWidgetItem(entry["Aday Ismi"])) + self.tableWidget.setItem(0, 2, QTableWidgetItem(entry["Mentor"])) + self.tableWidget.setItem(0, 3, QTableWidgetItem(entry["Degerlendirme"])) + self.tableWidget.setItem(0, 4, QTableWidgetItem(entry["dil seviyesi"])) + + def clear_table(self): + self.tableWidget.setRowCount(0) + + def comboBoxFilter(self): + filteredData = [] + data = self.sqlData() + for i in data: + if i["Degerlendirme"] not in filteredData: + filteredData.append(i["Degerlendirme"]) + else: + continue + return filteredData + + def showCombo(self): + selected = self.comboBox.currentText() + sqlData = self.sqlData() + filteredData = [item for item in sqlData if item["Degerlendirme"] == selected] + self.tableWidget.setRowCount(len(filteredData)) + + for i,j in enumerate(filteredData): + self.tableWidget.setItem(i, 0, QTableWidgetItem(str(j.get("Tarih", "")))) + self.tableWidget.setItem(i, 1, QTableWidgetItem(j.get("Aday Ismi", ""))) + self.tableWidget.setItem(i, 2, QTableWidgetItem(str(j.get("Mentor", "")))) + self.tableWidget.setItem(i, 3, QTableWidgetItem(j.get("Degerlendirme", ""))) + self.tableWidget.setItem(i, 4, QTableWidgetItem(j.get("dil seviyesi", ""))) + + def showAll(self): + sqlData = self.sqlData() + self.tableWidget.setRowCount(len(sqlData)) + for i,j in enumerate(sqlData): + self.tableWidget.setItem(i, 0, QTableWidgetItem(str(j.get("Tarih", "")))) + self.tableWidget.setItem(i, 1, QTableWidgetItem(j.get("Aday Ismi", ""))) + self.tableWidget.setItem(i, 2, QTableWidgetItem(str(j.get("Mentor", "")))) + self.tableWidget.setItem(i, 3, QTableWidgetItem(j.get("Degerlendirme", ""))) + self.tableWidget.setItem(i, 4, QTableWidgetItem(j.get("dil seviyesi", ""))) + + def exit(self): + QtWidgets.QApplication.quit() + + + def preference(self): + state = self.roleJson() + if state["login"] == "admin": + self.userWindow = QtWidgets.QWidget() + self.user_ui = Ui_Form_Admin() + self.user_ui.setupUi(self.userWindow) + self.userWindow.show() + MainWindow.close() + elif state["login"] == "user": + self.adminWindow = QtWidgets.QWidget() + self.adminUi = Ui_Form() + self.adminUi.setupUi(self.adminWindow) + self.adminWindow.show() + MainWindow.close() + else: + print("calismadi") + + + + + +if __name__ == "__main__": + app = QtWidgets.QApplication(sys.argv) + MainWindow = QtWidgets.QMainWindow() + ui = Ui_mentorInterviewsWindow() + ui.setupUi(MainWindow) + MainWindow.show() + sys.exit(app.exec()) diff --git a/task_2_crm/python_files/role.json b/task_2_crm/python_files/role.json new file mode 100644 index 0000000..44cba19 --- /dev/null +++ b/task_2_crm/python_files/role.json @@ -0,0 +1,3 @@ +{ + "login": "admin" +} \ No newline at end of file From 36fa80e72eab4f702219d5c440d76575875d403a Mon Sep 17 00:00:00 2001 From: Eren Date: Thu, 27 Feb 2025 18:49:16 +0100 Subject: [PATCH 2/4] completed --- task_2_crm/python_files/adminmenu.py | 4 +- task_2_crm/python_files/applications_page.py | 525 ------------------- task_2_crm/python_files/interviews.py | 162 ++++-- 3 files changed, 106 insertions(+), 585 deletions(-) delete mode 100644 task_2_crm/python_files/applications_page.py diff --git a/task_2_crm/python_files/adminmenu.py b/task_2_crm/python_files/adminmenu.py index 4503fa5..7e0f55d 100644 --- a/task_2_crm/python_files/adminmenu.py +++ b/task_2_crm/python_files/adminmenu.py @@ -46,13 +46,13 @@ def __init__(self): self.back_button.clicked.connect(self.openFile) def roleJson(self): - with open(r'python_files\role.json', "r") as file: + with open(r'task_2_crm\python_files\role.json', "r") as file: data = json.load(file) return data def load_events(self): """'events.json' file loads event data and populates the table.""" - json_file_path = r"python_files\events.json" # Path to your events.json file in the project directory + json_file_path = r"task_2_crm\python_files\events.json" # Path to your events.json file in the project directory if not os.path.exists(json_file_path): QMessageBox.warning(self, "Error", f"{json_file_path} file not found!") return diff --git a/task_2_crm/python_files/applications_page.py b/task_2_crm/python_files/applications_page.py deleted file mode 100644 index 85d1cdb..0000000 --- a/task_2_crm/python_files/applications_page.py +++ /dev/null @@ -1,525 +0,0 @@ -import sys -import json -import os -from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QPushButton, QTableWidget, QTableWidgetItem, QLineEdit, QFrame, QMenuBar, QStatusBar, QCompleter, QMessageBox -from PyQt6.QtCore import QThread, pyqtSignal, Qt -from PyQt6.QtGui import QIcon, QFont,QColor -from PrefenceAdminMenu import Ui_Form_Admin -from PrefenceMenu import Ui_Form as Ui_Form_User - -############################################# -# DATA LOADING AND GOOGLE DRIVE FILE DOWNLOAD -############################################# - -class DataLoaderThread(QThread): - data_loaded = pyqtSignal(dict) # Emits a dictionary containing all JSON data - - def run(self): - self.basvurular = r"coverted_files/Basvurular.json" - self.kullanicilar = r"coverted_files/Kullanicilar.json" - self.Mentor = r"coverted_files/Mentor.json" - self.Mulakatlar = r"coverted_files/Mulakatlar.json" - try: - json_files = [self.basvurular, self.kullanicilar, self.Mentor, self.Mulakatlar] - self.json_data = {} - for file_name in json_files: - if os.path.exists(file_name): - with open(file_name, "r", encoding="utf-8") as file: - self.json_data[file_name] = json.load(file) - print(f"{file_name} loaded, record count: {len(self.json_data[file_name])}") - else: - print(f"Warning: {file_name} not found!") - # Use "Basvurular.json" as the main data source for applications. - self.data_loaded.emit(self.json_data) - except Exception as e: - print(f"Error while loading JSON data: {e}") - - -############################################# -# APPLICATION PAGE (Applications) -############################################# - -class ApplicationsPage(QMainWindow): - def __init__(self): - super().__init__() - self.basvurular = r"coverted_files/Basvurular.json" - - # window = ApplicationsPage() bu satır kaldırıldı. - - # Create the main layout and central widget - self.central_widget = QWidget(self) - self.setCentralWidget(self.central_widget) - - # Diğer sınıf içeriği burada kaldığı gibi kalmalı - - # Create a vertical layout for the main widget - self.main_layout = QVBoxLayout(self.central_widget) - - # Create the search bar and button - self.search_layout = QHBoxLayout() - self.search_input = QLineEdit(self) - self.search_input.setStyleSheet(""" - QLineEdit { - border: 2px solid #007acc; - border-radius: 8px; - padding: 6px; - font-size: 14px; - } - QLineEdit:focus { - border: 2px solid #005fa3; - } - """) - self.search_button = QPushButton("Search", self) - self.search_button.setIcon(QIcon("search_icon.png")) - self.search_button.setStyleSheet(""" - QPushButton { - background-color: #007acc; - color: white; - border-radius: 8px; - padding: 6px 12px; - font-weight: bold; - } - QPushButton:hover { - background-color: #005fa3; - } - QPushButton:pressed { - background-color: #003f73; - } - """) - self.search_layout.addWidget(self.search_input) - self.search_layout.addWidget(self.search_button) - self.main_layout.addLayout(self.search_layout) - - # Create the buttons layout - self.button_layout = QHBoxLayout() - self.all_apps_button = QPushButton("All Applications", self) - self.all_apps_button.setStyleSheet(""" - QPushButton { - background-color: #007acc; - color: white; - border-radius: 8px; - padding: 6px 12px; - font-weight: bold; - } - QPushButton:hover { - background-color: #005fa3; - } - QPushButton:pressed { - background-color: #003f73; - } - """) - self.mentor_undefined_button = QPushButton("Mentor Interview Undefined", self) - self.mentor_undefined_button.setStyleSheet(""" - QPushButton { - background-color: #007acc; - color: white; - border-radius: 8px; - padding: 6px 12px; - font-weight: bold; - } - QPushButton:hover { - background-color: #005fa3; - } - QPushButton:pressed { - background-color: #003f73; - } - """) - self.mentor_defined_button = QPushButton("Mentor Meeting Defined", self) - self.mentor_defined_button.setStyleSheet(""" - QPushButton { - background-color: #007acc; - color: white; - border-radius: 8px; - padding: 6px 12px; - font-weight: bold; - } - QPushButton:hover { - background-color: #005fa3; - } - QPushButton:pressed { - background-color: #003f73; - } - """) - self.filter_applications = QPushButton("Filter Applications", self) - self.filter_applications.setStyleSheet(""" - QPushButton { - background-color: #007acc; - color: white; - border-radius: 8px; - padding: 6px 12px; - font-weight: bold; - } - QPushButton:hover { - background-color: #005fa3; - } - QPushButton:pressed { - background-color: #003f73; - } - """) - self.previous_vit_check = QPushButton("Previous Vit Check", self) - self.previous_vit_check.setStyleSheet(""" - QPushButton { - background-color: #007acc; - color: white; - border-radius: 8px; - padding: 6px 12px; - font-weight: bold; - } - QPushButton:hover { - background-color: #005fa3; - } - QPushButton:pressed { - background-color: #003f73; - } - """) - self.duplicate_records = QPushButton("Duplicate Records", self) - self.duplicate_records.setStyleSheet(""" - QPushButton { - background-color: #007acc; - color: white; - border-radius: 8px; - padding: 6px 12px; - font-weight: bold; - } - QPushButton:hover { - background-color: #005fa3; - } - QPushButton:pressed { - background-color: #003f73; - } - """) - self.unique_records = QPushButton("Unique Records", self) - self.unique_records.setStyleSheet(""" - QPushButton { - background-color: #007acc; - color: white; - border-radius: 8px; - padding: 6px 12px; - font-weight: bold; - } - QPushButton:hover { - background-color: #005fa3; - } - QPushButton:pressed { - background-color: #003f73; - } - """) - - # Add buttons to the layout - self.button_layout.addWidget(self.all_apps_button) - self.button_layout.addWidget(self.mentor_undefined_button) - self.button_layout.addWidget(self.mentor_defined_button) - self.button_layout.addWidget(self.filter_applications) - self.button_layout.addWidget(self.previous_vit_check) - self.button_layout.addWidget(self.duplicate_records) - self.button_layout.addWidget(self.unique_records) - - self.main_layout.addLayout(self.button_layout) - - # Create the table layout - self.table_layout = QHBoxLayout() - self.applications_table = QTableWidget(self) - self.applications_table.setColumnCount(7) - self.applications_table.setHorizontalHeaderLabels( - ["ID", "Name", "E-mail", "Phone", "Status", "Mentor", "Interview Status"] - ) - - # Font settings for QTableWidget - font = QFont() - font.setPointSize(10) # Normal size for table font (smaller size) - self.applications_table.setFont(font) - - # Adjust row height and column width - self.applications_table.setRowHeight(0, 40) # Set row height for the first row - self.applications_table.setColumnWidth(0, 100) # Set column width for each column - self.applications_table.setColumnWidth(1, 200) - self.applications_table.setColumnWidth(2, 200) - self.applications_table.setColumnWidth(3, 150) - self.applications_table.setColumnWidth(4, 150) - self.applications_table.setColumnWidth(5, 200) - self.applications_table.setColumnWidth(6, 200) - - self.applications_table.setStyleSheet(""" - QTableWidget { - background: white; - border: none; - alternate-background-color: #f8f9fa; - gridline-color: #dee2e6; - } - QHeaderView::section { - background-color: #005fa3; - color: white; - font-weight: bold; - padding: 6px; - border: none; - } - QTableWidget::item { - padding: 10px; - border-bottom: 1px solid #dee2e6; - } - """) - self.table_layout.addWidget(self.applications_table) - self.main_layout.addLayout(self.table_layout) - - # Create the return button layout - self.return_button_layout = QVBoxLayout() - self.return_button = QPushButton("Return to Preferences Screen", self) - self.return_button.setStyleSheet(""" - QPushButton { - background-color: #d9534f; - color: white; - border-radius: 12px; - padding: 8px; - font-size: 14px; - font-weight: bold; - } - QPushButton:hover { - background-color: #c9302c; - } - """) - self.return_button_layout.addWidget(self.return_button) - self.main_layout.addLayout(self.return_button_layout) - - # Setup connections and load data - self.setup_connections() - self.data_loader = DataLoaderThread() - self.data_loader.data_loaded.connect(self.populate_table) - self.data_loader.start() - - - # Your class methods converted to PyQt6: - - def setup_connections(self): - # Connect buttons to their respective functions - self.search_button.clicked.connect(self.search_function) - self.all_apps_button.clicked.connect(self.show_all_data) - self.return_button.clicked.connect(self.return_to_preferences) - self.mentor_defined_button.clicked.connect(lambda: self.filter_by_mentor(True)) - self.mentor_undefined_button.clicked.connect(lambda: self.filter_by_mentor(False)) - self.filter_applications.clicked.connect(self.filter_applications_function) - self.previous_vit_check.clicked.connect(self.previous_vit_check_function) - self.duplicate_records.clicked.connect(self.duplicate_records_function) - self.unique_records.clicked.connect(self.unique_records_function) - - def populate_table(self, json_data): - # Get the application data from "Basvurular.json" - self.all_data = json_data.get(self.basvurular, []) - print(f"Application data loaded, total records: {len(self.all_data)}") - self.display_data(self.all_data) - - # Extract names for autocomplete functionality - self.names = [entry.get("Adınız Soyadınız") for entry in self.all_data] - - # Now, setup autocomplete after names have been loaded - self.setup_autocomplete() - - def display_data(self, data): - # Define a mapping from Turkish keys (in your JSON) to English column headers. - mapping = { - "Zaman damgası": "Timestamp", - "Adınız Soyadınız": "Name", - "Mail adresiniz": "Email", - "Telefon Numaranız": "Phone", - "Şu anki durumunuz": "Current Status", - "Basvuru Donemi": "Application Period" - } - # Get the list of English headers from the mapping. - english_columns = list(mapping.values()) - self.applications_table.setColumnCount(len(english_columns)) - self.applications_table.setHorizontalHeaderLabels(english_columns) - self.applications_table.setRowCount(len(data)) - for row, entry in enumerate(data): - for col, (turkish_key, english_label) in enumerate(mapping.items()): - value = str(entry.get(turkish_key, "")) - item = QTableWidgetItem(value) - item.setToolTip(value) - item.setBackground(QColor(240, 240, 240)) - item.setForeground(QColor("black")) - # Set the tooltip for each item in the table - item.setToolTip(value) # Show the full content when hovered - self.applications_table.setItem(row, col, item) - - def setup_autocomplete(self): - # Create a QCompleter for autocomplete based on the names list - completer = QCompleter(self.names) - completer.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive) # Make the search case-insensitive - self.search_input.setCompleter(completer) - - # Connect the textChanged signal to update search results - self.search_input.textChanged.connect(self.update_search_results) - - def update_search_results(self, text): - # Filter the application data based on the search input text - if text: - filtered_data = [entry for entry in self.all_data if text.lower() in entry["Adınız Soyadınız"].lower()] - self.display_data(filtered_data) - else: - self.display_data(self.all_data) - - def search_function(self): - search_text = self.search_input.text().strip().lower() - print(f"Searching for: {search_text}") - for row in range(self.applications_table.rowCount()): - match_found = any( - search_text in (self.applications_table.item(row, col).text().lower() - if self.applications_table.item(row, col) else "") - for col in range(self.applications_table.columnCount()) - ) - self.applications_table.setRowHidden(row, not match_found) - - def show_all_data(self): - print("Showing all applications.") - self.display_data(self.all_data) - def jsonRole(self): - with open(r"python_files\role.json","r") as file: - data = json.load(file) - return data - - def return_to_preferences(self): - jsonData = self.jsonRole() - self.userWindow = QWidget() - if jsonData["login"] == "user": - self.user_ui = Ui_Form_User() - - else: - self.user_ui = Ui_Form_Admin() - - self.user_ui.setupUi(self.userWindow) - - self.userWindow.show() - self.close() # Mevcut pencereyi kapat - - def filter_by_mentor(self, has_mentor): - # In the applications JSON, mentor assignment is stored under the key "Mentor gorusmesi". - filtered_data = [entry for entry in self.all_data if bool(entry.get("Mentor gorusmesi")) == has_mentor] - print(f"Filtering by mentor ({has_mentor}): {len(filtered_data)} records found.") - self.display_data(filtered_data) - - def duplicate_records_function(self): - seen = {} - duplicates = [] - for entry in self.all_data: - key = (entry.get("Adınız Soyadınız"), entry.get("Mail adresiniz"), entry.get("Telefon Numaranız")) - if key in seen: - duplicates.append(entry) - else: - seen[key] = entry - print(f"Duplicate records found: {len(duplicates)}") - self.display_data(duplicates) - - def unique_records_function(self): - unique_data = { - (entry.get("Adınız Soyadınız"), entry.get("Mail adresiniz"), entry.get("Telefon Numaranız")): entry - for entry in self.all_data} - self.display_data(list(unique_data.values())) - - def filter_applications_function(self): - try: - # 'Basvurular.json' dosyasını yükleyelim - with open(self.basvurular, 'r', encoding='utf-8') as f: - all_entries = json.load(f) # 'Basvurular.json' dosyasındaki veriyi al - - # Eğer dosyada hiç veri yoksa - if not all_entries: - print("No data found in Basvurular.json.") - QMessageBox.warning(self, "Warning", "No application records found in Basvurular.json!") - return - - # Kişilerin kaç kez başvurduklarını saymak için email veya soyadı kullanıyoruz - identifier_counts = {} - duplicate_entries = {} # Duplicate entries dictionary - - # Kişilerin başvurularını saymak - for entry in all_entries: - # Öncelikle Mail adresini kullan, yoksa Ad-Soyad kullan - identifier = (entry.get("Mail adresiniz") or entry.get("Adınız Soyadınız")).strip() if ( - entry.get("Mail adresiniz") or entry.get("Adınız Soyadınız")) else None - if identifier: # Geçerli bir identifier var mı kontrol et - if identifier in identifier_counts: - identifier_counts[identifier] += 1 - else: - identifier_counts[identifier] = 1 - - # Duplicate kayıtları buluyoruz ve bunları dictionary'e ekliyoruz - for entry in all_entries: - identifier = (entry.get("Mail adresiniz") or entry.get("Adınız Soyadınız")).strip() if ( - entry.get("Mail adresiniz") or entry.get("Adınız Soyadınız")) else None - if identifier and identifier_counts[identifier] > 1: - if identifier not in duplicate_entries: - # Kişiyi ve başvuru sayısını kaydedelim - entry["Tekrar Sayısı"] = identifier_counts[identifier] - duplicate_entries[identifier] = entry # Her kişiyi yalnızca bir kez ekle - - if not duplicate_entries: # Eğer hiç duplicate yoksa - QMessageBox.warning(self, "Warning", "No one found with multiple submissions.") - return - - # MessageBox'a yazılacak mesajı hazırlayalım - duplicate_info = f"Found {len(duplicate_entries)} users with multiple submissions:/n/n" - - for identifier, entry in duplicate_entries.items(): - name = entry.get("Adınız Soyadınız") - email = entry.get("Mail adresiniz") - repeat_count = entry.get("Tekrar Sayısı") - - # None veya boş veri kontrolü yapalım - if name and email: # Name ve email boş değilse - duplicate_info += f"- {name} ({email}) submitted {repeat_count} times./n" - - # None veya eksik değer olanları dışarıda bırakıyoruz - if duplicate_info.strip(): # Eğer mesaj boş değilse - QMessageBox.information(self, "Multiple Submissions Found", duplicate_info) - - # Debug için count bilgilerini yazdırıyoruz - print("Duplicate count per identifier:") - for identifier, count in identifier_counts.items(): - if count > 1: - print(f"{identifier}: {count} times") - - except Exception as e: - print(f"Error in filter_applications_function: {e}") - - - def previous_vit_check_function(self): - try: - # JSON dosyasını oku - file_path = r"coverted_files/Basvurular.json" # Dosyanın yolu - try: - with open(file_path, "r", encoding="utf-8") as file: - self.all_data = json.load(file) # JSON verisini yükle - except FileNotFoundError: - QMessageBox.critical(self, "Error", f"File '{file_path}' not found!") - return - except json.JSONDecodeError: - QMessageBox.critical(self, "Error", f"Invalid JSON format in '{file_path}'!") - return - - # JSON verisi boş mu? - if not self.all_data: - print("No JSON data loaded.") - QMessageBox.warning(self, "Warning", "No student records matching the filtered criteria were found!") - return - - # VIT3 harici kişileri bul - vit_data = [entry for entry in self.all_data if "VIT3" not in str(entry.values())] - - if not vit_data: # Eğer hiç VIT3 harici kişi yoksa - QMessageBox.warning(self, "Warning", "No student records matching the filtered criteria were found!") - return - - # Filtrelenen verileri tabloya yazdır - print(f"Found {len(vit_data)} records excluding VIT3.") - self.display_data(vit_data) - - except Exception as e: - print(f"Error in previous_vit_check_function: {e}") - - -if __name__ == "__main__": - app = QApplication(sys.argv) - window = ApplicationsPage() - window.setWindowTitle("Applications") - window.setWindowIcon(QIcon("app_icon.png")) - window.resize(800, 600) - window.show() - sys.exit(app.exec()) \ No newline at end of file diff --git a/task_2_crm/python_files/interviews.py b/task_2_crm/python_files/interviews.py index 574e9b7..ffd147d 100644 --- a/task_2_crm/python_files/interviews.py +++ b/task_2_crm/python_files/interviews.py @@ -1,15 +1,15 @@ +import json + from PyQt6 import QtCore, QtWidgets from PyQt6.QtWidgets import QCompleter, QTableWidgetItem -import json,sys +import sys +import psycopg2 from PrefenceAdminMenu import Ui_Form_Admin from PrefenceMenu import Ui_Form - - - class Ui_interviewsWindow(object): - + def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(854, 569) @@ -144,7 +144,7 @@ def retranslateUi(self, MainWindow): self.lineEdit_input.setPlaceholderText(_translate("MainWindow", "Enter text to search..")) - #calling methods + # Calling methods self.setup_completer() self.pushButton_search.clicked.connect(self.search_data) self.pushButton_project_sended.clicked.connect(self.sended) @@ -152,80 +152,128 @@ def retranslateUi(self, MainWindow): self.pushButton_exit.clicked.connect(self.exit) self.pushButton_prefence.clicked.connect(self.preference) - def jsonData(self): - jsonPath = r'coverted_files\Mulakatlar.json' - with open(jsonPath, 'r', encoding='utf-8') as file: - data = json.load(file) - return data - + db_params = { + "host": "localhost", + "port": "5432", + "dbname": "CRM", + "user": "postgres", + "password": "sunset2014" + } + + def fetchDataFromDB(self): + """ Veritabanından mülakat verilerini çeker """ + connection = psycopg2.connect( + host=self.db_params["host"], + port=self.db_params["port"], + dbname=self.db_params["dbname"], + user=self.db_params["user"], + password=self.db_params["password"] + ) + cursor = connection.cursor() + + query = '''SELECT "Adınız Soyadınız", "Proje gonderilis tarihi", "Projenin gelis tarihi" FROM Mulakatlar''' + cursor.execute(query) + data = cursor.fetchall() + + formatted_data = [ + { + "Adınız Soyadınız": row[0], + "Proje gonderilis tarihi": row[1] if row[1] else "", + "Projenin gelis tarihi": row[2] if row[2] else "" + } + for row in data + ] + + connection.close() + return formatted_data + + + def roleJson(self): - jsonPath = r"python_files\role.json" + jsonPath = r"task_2_crm\python_files\role.json" with open(jsonPath, 'r', encoding="utf-8") as file: data = json.load(file) return data - + def setup_completer(self): - data = self.jsonData() - names = [entry["Adınız Soyadınız"] for entry in data] + """ Otomatik tamamlamayı veritabanından çeker """ + data = self.fetchDataFromDB() + names = [entry['Adınız Soyadınız'] for entry in data] completer = QCompleter(names) completer.setCaseSensitivity(QtCore.Qt.CaseSensitivity.CaseInsensitive) self.lineEdit_input.setCompleter(completer) def search_data(self): - data = self.jsonData() - search_name = self.lineEdit_input.text().lower() - if not search_name: - return - found = False - for entry in data: - if search_name in entry["Adınız Soyadınız"].lower(): - self.update_table(entry) - found = True - break - if not found: - self.clear_table() - - def update_table(self, entry): - self.columnView.setRowCount(1) - self.columnView.setItem(0, 0, QTableWidgetItem(entry["Adınız Soyadınız"])) - self.columnView.setItem(0, 1, QTableWidgetItem(entry["Proje gonderilis tarihi"])) - self.columnView.setItem(0, 2, QTableWidgetItem(entry["Projenin gelis tarihi"])) - - - def clear_table(self): - self.columnView.setRowCount(0) + """ Arama işlemini gerçekleştir """ + search_text = self.lineEdit_input.text().lower() + query = '''SELECT "Adınız Soyadınız", "Proje gonderilis tarihi", "Projenin gelis tarihi" + FROM Mulakatlar WHERE LOWER("Adınız Soyadınız") LIKE %s''' + connection = psycopg2.connect( + host=self.db_params["host"], + port=self.db_params["port"], + dbname=self.db_params["dbname"], + user=self.db_params["user"], + password=self.db_params["password"] + ) + cursor = connection.cursor() + + cursor.execute(query, (f"%{search_text}%",)) + data = cursor.fetchall() + + self.columnView.setRowCount(len(data)) + for row_idx, row in enumerate(data): + for col_idx, value in enumerate(row): + item = QTableWidgetItem(str(value)) + self.columnView.setItem(row_idx, col_idx, item) + connection.close() def sended(self): - jsonData = self.jsonData() - sendedItem = [item for item in jsonData if item["Proje gonderilis tarihi"]] - self.columnView.setRowCount(len(sendedItem)) - for i,j in enumerate(sendedItem): - self.columnView.setItem(i, 0, QTableWidgetItem(str(j.get("Adınız Soyadınız")))) - self.columnView.setItem(i, 1, QTableWidgetItem(str(j.get("Proje gonderilis tarihi")))) - self.columnView.setItem(i, 2, QTableWidgetItem(str(j.get("Projenin gelis tarihi")))) + """ Gönderilen projeleri göster """ + query = '''SELECT "Adınız Soyadınız", "Proje gonderilis tarihi", "Projenin gelis tarihi" + FROM Mulakatlar WHERE "Proje gonderilis tarihi" IS NOT NULL''' + self.fetchAndDisplay(query) def arrived(self): - jsonData = self.jsonData() - arrivedItem = [item for item in jsonData if item['Projenin gelis tarihi']] - self.columnView.setRowCount(len(arrivedItem)) - for i,j in enumerate(arrivedItem): - self.columnView.setItem(i, 0, QTableWidgetItem(str(j.get("Adınız Soyadınız")))) - self.columnView.setItem(i, 1, QTableWidgetItem(str(j.get("Proje gonderilis tarihi")))) - self.columnView.setItem(i, 2, QTableWidgetItem(str(j.get("Projenin gelis tarihi")))) + """ Ulaşan projeleri göster """ + query = '''SELECT "Adınız Soyadınız", "Proje gonderilis tarihi", "Projenin gelis tarihi" + FROM Mulakatlar WHERE "Projenin gelis tarihi" IS NOT NULL''' + self.fetchAndDisplay(query) + + def fetchAndDisplay(self, query): + """ Veritabanından verileri çek ve tablonun içine yerleştir """ + connection = psycopg2.connect( + host=self.db_params["host"], + port=self.db_params["port"], + dbname=self.db_params["dbname"], + user=self.db_params["user"], + password=self.db_params["password"] + ) + cursor = connection.cursor() + cursor.execute(query) + data = cursor.fetchall() + self.columnView.setRowCount(len(data)) + + for row_idx, row in enumerate(data): + for col_idx, value in enumerate(row): + item = QTableWidgetItem(str(value)) + self.columnView.setItem(row_idx, col_idx, item) + + connection.close() def exit(self): - QtWidgets.QApplication.quit() + """ Uygulamadan çık """ + sys.exit() def preference(self): state = self.roleJson() - if state["login"] == "admin": + if state["login"] == "admin": self.userWindow = QtWidgets.QWidget() self.user_ui = Ui_Form_Admin() self.user_ui.setupUi(self.userWindow) self.userWindow.show() - MainWindow.close() + MainWindow.close() elif state["login"] == "user": self.adminWindow = QtWidgets.QWidget() self.adminUi = Ui_Form() @@ -235,12 +283,10 @@ def preference(self): else: print("calismadi") - - if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_interviewsWindow() ui.setupUi(MainWindow) MainWindow.show() - sys.exit(app.exec()) + sys.exit(app.exec()) \ No newline at end of file From 0be7f931fa94879c4830aee04c7d1fcc675d833d Mon Sep 17 00:00:00 2001 From: Eren Date: Thu, 27 Feb 2025 18:52:22 +0100 Subject: [PATCH 3/4] quick fix --- task_2_crm/python_files/fetching.py | 2 +- task_2_crm/python_files/interviews.py | 2 +- task_2_crm/python_files/loginscreen.py | 2 +- task_2_crm/python_files/mentor_interview.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/task_2_crm/python_files/fetching.py b/task_2_crm/python_files/fetching.py index c601e56..ba6a0d7 100644 --- a/task_2_crm/python_files/fetching.py +++ b/task_2_crm/python_files/fetching.py @@ -44,7 +44,7 @@ conn = psycopg2.connect( dbname="CRM", user="postgres", - password="sunset2014", + password="", host="localhost", port="5432" ) diff --git a/task_2_crm/python_files/interviews.py b/task_2_crm/python_files/interviews.py index ffd147d..12f7ba7 100644 --- a/task_2_crm/python_files/interviews.py +++ b/task_2_crm/python_files/interviews.py @@ -157,7 +157,7 @@ def retranslateUi(self, MainWindow): "port": "5432", "dbname": "CRM", "user": "postgres", - "password": "sunset2014" + "password": "" } def fetchDataFromDB(self): diff --git a/task_2_crm/python_files/loginscreen.py b/task_2_crm/python_files/loginscreen.py index ba1d027..b147c20 100644 --- a/task_2_crm/python_files/loginscreen.py +++ b/task_2_crm/python_files/loginscreen.py @@ -10,7 +10,7 @@ DB_CONFIG = { "dbname": "CRM", "user": "postgres", - "password": "sunset2014", + "password": "", "host": "localhost", "port": "5432" } diff --git a/task_2_crm/python_files/mentor_interview.py b/task_2_crm/python_files/mentor_interview.py index c505b33..9aa8b2f 100644 --- a/task_2_crm/python_files/mentor_interview.py +++ b/task_2_crm/python_files/mentor_interview.py @@ -118,7 +118,7 @@ def sqlData(self): con = psycopg2.connect( dbname="CRM", user="postgres", - password="sunset2014", + password="", host="localhost", port="5432" ) From d0ac1b6ecee7a70050c7759e52ac5fa09d8fbefb Mon Sep 17 00:00:00 2001 From: Eren Date: Fri, 28 Feb 2025 15:50:59 +0100 Subject: [PATCH 4/4] task1 completed --- task_1/task1.py | 60 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/task_1/task1.py b/task_1/task1.py index 981503a..5ea85a1 100644 --- a/task_1/task1.py +++ b/task_1/task1.py @@ -79,10 +79,58 @@ question2 = cur.fetchall() print(question2) print("________________question3_______________") +query_3 = """SELECT first_name, last_name, salary FROM public.employees_table +where salary > 8700;""" +cur.execute(query_3) +question3 = cur.fetchall() +print(question3) +print("________________question4_______________") +query_4 = """SELECT first_name, last_name from employees_table +where emp_id in (select emp_id from departments_table)""" +cur.execute(query_4) +question4 = cur.fetchall() +print(question4) +print("________________question5_______________") +query_5 = """SELECT first_name, last_name from employees_table +where emp_id in (select emp_id from departments_table where dept_name = 'Technology')""" +cur.execute(query_5) +question5 = cur.fetchall() +print(question5) +print("________________question6_______________") +query6 = """select avg(salary) from employees_table +where gender = 'Female'""" +query_6 = """select avg(salary) from employees_table +where gender = 'Female'""" +cur.execute(query_6) +question6 = cur.fetchall() +print(question6) +print("________________question7_______________") +query7 = """SELECT dept_name, AVG(salary) AS avg_salary +FROM employees_table e +JOIN departments_table d +ON e.emp_id = d.emp_id +GROUP BY d.dept_name; +""" +cur.execute(query7) +question7 = cur.fetchall() +print(question7) +print("________________question8_______________") +query_8 = """select max(hire_date), min(hire_date) from employees_table""" +cur.execute(query_8) +question8 = cur.fetchall() +print(question8) +print("________________question9_______________") +query9 = """select hire_date, dept_name from employees_table e +join departments_table d on e.emp_id = d.emp_id +where e.salary = (select max(salary) from employees_table)""" +cur.execute(query9) +question9 = cur.fetchall() +print(question9) +print("________________question10_______________") +query10 = """select hire_date from employees_table where salary = (select min(salary) from employees_table)""" +cur.execute(query10) +question10 = cur.fetchall() +print(question10) - - - - - -cur.close() \ No newline at end of file +cur.close() +con.close() \ No newline at end of file