diff --git a/ITP3915-programming-fundamentals/.editorconfig b/ITP3915-programming-fundamentals/.editorconfig new file mode 100644 index 0000000..7c66b50 --- /dev/null +++ b/ITP3915-programming-fundamentals/.editorconfig @@ -0,0 +1,15 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false + +[*.md] +trim_trailing_whitespace = false diff --git a/ITP3915-programming-fundamentals/.gitignore b/ITP3915-programming-fundamentals/.gitignore new file mode 100644 index 0000000..a45995f --- /dev/null +++ b/ITP3915-programming-fundamentals/.gitignore @@ -0,0 +1,168 @@ +~*.* + +# Created by https://www.toptal.com/developers/gitignore/api/python +# Edit at https://www.toptal.com/developers/gitignore?templates=python + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# End of https://www.toptal.com/developers/gitignore/api/python \ No newline at end of file diff --git a/ITP3915-programming-fundamentals/Assignment to student.pdf b/ITP3915-programming-fundamentals/Assignment to student.pdf new file mode 100644 index 0000000..c39eeee Binary files /dev/null and b/ITP3915-programming-fundamentals/Assignment to student.pdf differ diff --git a/ITP3915-programming-fundamentals/docs/README.md b/ITP3915-programming-fundamentals/docs/README.md new file mode 100644 index 0000000..bc18f04 --- /dev/null +++ b/ITP3915-programming-fundamentals/docs/README.md @@ -0,0 +1,7 @@ +# MENTIONS: + +### word test_plan.docx +![](./f3wV3PnOix.png) + +### need to brief ? +![](./need_to_brief.png) diff --git a/ITP3915-programming-fundamentals/docs/f3wV3PnOix.png b/ITP3915-programming-fundamentals/docs/f3wV3PnOix.png new file mode 100644 index 0000000..a4a1943 --- /dev/null +++ b/ITP3915-programming-fundamentals/docs/f3wV3PnOix.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c673c7404d6bf72a13804d5041597d3fc950c6f5a5c357b4a997e4b2fa73869d +size 89017 diff --git a/ITP3915-programming-fundamentals/docs/need_to_brief.png b/ITP3915-programming-fundamentals/docs/need_to_brief.png new file mode 100644 index 0000000..cb850bf --- /dev/null +++ b/ITP3915-programming-fundamentals/docs/need_to_brief.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:35d22f5a364dc42499159eb76f6283f79f2660a3d052fdb2fb4d8b2c4f6a0adb +size 105247 diff --git a/ITP3915-programming-fundamentals/employee_list.txt b/ITP3915-programming-fundamentals/employee_list.txt new file mode 100644 index 0000000..644b388 --- /dev/null +++ b/ITP3915-programming-fundamentals/employee_list.txt @@ -0,0 +1,13 @@ +# A list containing all the employee details in this system +# Comments and empty lines are ignored +# Details are in the following pattern +# Employee ID, Employee Name, Salary, Department + +IVE00001, Kelvin Yip, 43210.5, IT +IVE00002, Cow Leung, 32105.4, Admin +IVE00003, Leung Pig Hung, 21054.3, HR +IVE00004, Michael Fung, 10543.2, Finance +IVE00005, Joe Yeung, 6543.2, IT +IVE00006, Martin Kung, 5432.1, Admin + + diff --git a/ITP3915-programming-fundamentals/employee_list_old.txt b/ITP3915-programming-fundamentals/employee_list_old.txt new file mode 100644 index 0000000..644b388 --- /dev/null +++ b/ITP3915-programming-fundamentals/employee_list_old.txt @@ -0,0 +1,13 @@ +# A list containing all the employee details in this system +# Comments and empty lines are ignored +# Details are in the following pattern +# Employee ID, Employee Name, Salary, Department + +IVE00001, Kelvin Yip, 43210.5, IT +IVE00002, Cow Leung, 32105.4, Admin +IVE00003, Leung Pig Hung, 21054.3, HR +IVE00004, Michael Fung, 10543.2, Finance +IVE00005, Joe Yeung, 6543.2, IT +IVE00006, Martin Kung, 5432.1, Admin + + diff --git a/ITP3915-programming-fundamentals/gen_markdown_table.py b/ITP3915-programming-fundamentals/gen_markdown_table.py new file mode 100644 index 0000000..a3a68fb --- /dev/null +++ b/ITP3915-programming-fundamentals/gen_markdown_table.py @@ -0,0 +1,477 @@ +import sys + +table_template = ''' +| ID | Test Case Name | Procedure | Expected Output | Screen Dump | Result | +|----|----------------|-----------|-----------------|-------------|--------| +{{{rows}}} +'''.strip() + +row_template=''' +| 1 | 2 | 3 | 4 | 5 | 6 | +'''.strip() + +cases = [ +{ + 'test_case_name':"Display all employees in the system", + 'procedure':''' +1. Start program. +2. input 1 for display all employee + '''.strip(), + 'expected_output':" All employees' information including their employee ID, name, salary and department should be displayed", + 'screen_dump':"![](./screenshots/test1.png)", + 'result':"Pass/ ~~Fail~~" +}, + + +{ + 'test_case_name':'''Add an employee with name "Pika Chiu, salary 15000 and wortks in IT department into the system''', + 'procedure':''' +1. In the employee management system menu, input '2' to add an employee +2. Input 'Pika Chiu' for employee's name Input "15000" for salary +3. Input "IT" for IT department + '''.strip(), + 'expected_output':'''A success message "Employee Added Successfully" should be displayed''', + 'screen_dump':"![](./screenshots/test2.png)", + 'result':"Pass/ ~~Fail~~" +}, + + +{ + 'test_case_name':'''Remove an employee with valid employee id''', + 'procedure':''' +1. In the employee management system menu, input '3' to Remove an employee +2. Input 'IVE00006' for employee's id + '''.strip(), + 'expected_output':'''A success message "Employee Removed Successfully" should be displayed''', + 'screen_dump':"![](./screenshots/test3.png)", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''Update an employee with valid employee id''', + 'procedure':''' +1. In the employee management system menu, input '4' to Update an employee +2. Input 'IVE00005' for employee's id +3. Input '99999' for employee's salary + '''.strip(), + 'expected_output':'''A success message "Employee Updated Successfully" should be displayed''', + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''Display company statistics''', + 'procedure':''' +1. In the employee management system menu, input '5' to Update an employee + '''.strip(), + 'expected_output':''' +1. a list of all employee information listed +2. total number of staff listed +3. staff with highest salary listed +4. staff with lowest salary listed +5. average salary listed + ''', + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''exiting system''', + 'procedure':''' +1. In the employee management system menu, input "ENTER"(enter key) to exit system + '''.strip(), + 'expected_output':''' +1. system exit + ''', + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''main menu invalid input handling''', + 'procedure':''' +1. In the employee management system menu, input "~" to main menu + '''.strip(), + 'expected_output':''' +1. screen showing "input digit contains non-int value, accepted values are 1,2,3,4,5" alert to user + ''', + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''main menu invalid input handling''', + 'procedure':''' +1. In the employee management system menu, input "a" to main menu + '''.strip(), + 'expected_output':''' +1. screen showing "input digit contains non-int value, accepted values are 1,2,3,4,5" alert to user + ''', + 'result':"Pass/ ~~Fail~~" +}, + + +{ + 'test_case_name':'''Add an employee (invalid employee name)''', + 'procedure':''' +1. In the employee management system menu, input '2' to add an employee +2. Input 'a1' for employee's name (this is invalid name) +3. Input '123' for employee's name (this is invalid name) +4. Input '4a' for employee's name (this is valid name) +5. Input 'apple' for employee's name (this is valid name) +6. Input "99999" for salary +7. Input "IT" for IT department + '''.strip(), + 'expected_output':''' +1. showing "ERROR: sorry but the employee name should not contain digit" alert to user +2. keep asking "Please input employee's name, Enter to return:" until valid name get +3. after getting apple as name, get back to normal employee adding flow + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''Add an employee (invalid employee salary)''', + 'procedure':''' +1. In the employee management system menu, input '2' to add an employee +2. Input 'apple' for employee's name (this is valid name) +3. Input "aaaaa" for salary (invalid input as contains text) +4. Input "11111" for salary (valid input) +5. Input "IT" for IT department + '''.strip(), + 'expected_output':''' +1. showing "ERROR: Employee's salary contains non digit value" alert to user +2. keep asking "Please input employee's salary, Enter to return:" until valid salary get +3. after getting valid salary, get back to normal employee adding flow + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + + +{ + 'test_case_name':'''Add an employee (invalid employee department)''', + 'procedure':''' +1. In the employee management system menu, input '2' to add an employee +2. Input 'apple' for employee's name (this is valid name) +3. Input "11111" for salary (valid input) +4. Input "Marketing" (invalid input) +5. Input "IT" (valid input) + '''.strip(), + 'expected_output':''' +1. showing "ERROR: Not a valid department, the valid options are HR, IT, Admin, Finance" alert to user +2. keep asking "Please input employee's department, Enter to return:" until valid department get +3. after getting valid department, show "***** Employee Added Successfully" + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + + +{ + 'test_case_name':'''Remove an employee (invalid employee id, not existing)''', + 'procedure':''' +1. In the employee management system menu, input '3' to remove an employee +2. Input 'IVE00007' for employee's id (this is invalid id, not exist) +2. Input "IVE00006" for employee's id (valid input, existing id) + '''.strip(), + 'expected_output':''' +1. showing "ERROR: sorry but the input id not found" alert to user +2. keep asking "Please input employee's id, Enter to return:" until valid id get +3. after getting valid id, show "***** Employee Removed Successfully" + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''Remove an employee (invalid employee id, invalid format)''', + 'procedure':''' +1. In the employee management system menu, input '3' to remove an employee +2. Input 'III00007' for employee's id (this is invalid id, not exist) +2. Input "IVE00006" for employee's id (valid input, existing id) + '''.strip(), + 'expected_output':''' +1. showing "ERROR: sorry but the input id not found" alert to user +2. keep asking "Please input employee's id, Enter to return:" until valid id get +3. after getting valid id, show "***** Employee Removed Successfully" + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + + +{ + 'test_case_name':'''Remove an employee (invalid employee id, invalid format)''', + 'procedure':''' +1. In the employee management system menu, input '3' to remove an employee +2. Input 'a' for employee's id (this is invalid id) +2. Input "IVE00006" for employee's id (valid input, existing id) + '''.strip(), + 'expected_output':''' +1. showing "ERROR: sorry but the input id not found" alert to user +2. keep asking "Please input employee's id, Enter to return:" until valid id get +3. after getting valid id, show "***** Employee Removed Successfully" + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''Remove an employee (invalid employee id, invalid format)''', + 'procedure':''' +1. In the employee management system menu, input '3' to remove an employee +2. Input '11111111' for employee's id (this is invalid id) +3. Input "IVE00006" for employee's id (valid input, existing id) + '''.strip(), + 'expected_output':''' +1. showing "ERROR: sorry but the input id not found" alert to user +2. keep asking "Please input employee's id, Enter to return:" until valid id get +3. after getting valid id, show "***** Employee Removed Successfully" + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''Update an employee (invalid employee id, invalid format)''', + 'procedure':''' +1. In the employee management system menu, input '4' to update an employee +2. Input '1' for employee's id (this is invalid id) +3. Input "IVE00006" for employee's id (valid input, existing id) +4. Input "11111" for employee's id (valid input) + '''.strip(), + 'expected_output':''' +1. showing "ERROR: sorry but the input id not found" alert to user +2. keep asking "Please input employee's id, Enter to return:" until valid id get +3. after getting valid id, get back to normal update employee flow + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''Update an employee (invalid salary)''', + 'procedure':''' +1. In the employee management system menu, input '4' to update an employee +2. Input "IVE00006" for employee's id (valid employee id, existing id) +3. Input "a" for salary (invalid input, salary cannot be non integer value) +4. Input "$" for salary (invalid input, salary cannot be non integer value) +5. Input "111" for salary (value input, integer value only) + '''.strip(), + 'expected_output':''' +1. showing "ERROR: Employee's salary contains non digit value" alert to user +2. keep asking "Please input employee's salary, Enter to return:" until valid salary get +3. after getting valid salary, show "***** Employee Updated Successfully" to user + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''display highest salary''', + 'procedure':''' +1. In the employee management system menu, input '5' get current snap of employee table +2. In the employee management system menu, input '2' to add an employee +3. Input "highest_employee" for name (valid employee name) +4. Input "9999999" for salary (valid highest salary) +5. Input "IT" for department (valid department) +6. Input "5" to check the highest salary got updated + '''.strip(), + 'expected_output':''' +1. showing "highest_employee" in staff name field with highest salary + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''display lowest salary''', + 'procedure':''' +1. In the employee management system menu, input '5' get current snap of employee table +2. In the employee management system menu, input '2' to add an employee +3. Input "lowest_employee" for name (valid employee name) +4. Input "10" for salary (valid lowest salary) +5. Input "IT" for department (valid department) +6. Input "5" to check the lowest salary got updated + '''.strip(), + 'expected_output':''' +1. showing "lowest_employee" in staff name field with lowest salary + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''update statistics after adding user''', + 'procedure':''' +1. In the employee management system menu, input '5' get current snap of employee table +2. In the employee management system menu, input '2' to add an employee +3. Input "new_user" for name (valid employee name) +4. Input "10" for salary (valid high salary) +5. Input "IT" for department (valid department) +6. Input "5" to check the lowest salary got updated + '''.strip(), + 'expected_output':''' +1. number of staff = "6" + "1" = "7" + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''update statistics after remove user''', + 'procedure':''' +1. In the employee management system menu, input '5' get current snap of employee table +2. In the employee management system menu, input '3' to remove an employee +3. Input "IVE00006" for id (valid employee id) + '''.strip(), + 'expected_output':''' +1. number of staff = "6" - "1" = "5" + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''update average after adding user''', + 'procedure':''' +1. In the employee management system menu, input '5' get current snap of employee table +2. In the employee management system menu, input '2' to add an employee +3. Input "new_user" for name (valid employee name) +4. Input "10" for salary (valid high salary) +5. Input "IT" for department (valid department) +6. Input "5" to check the average salary got updated + '''.strip(), + 'expected_output':''' +1. average salary changed from $19814.78 to $16,985.53 (average of "7" employee) + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''update average after remove user''', + 'procedure':''' +1. In the employee management system menu, input '5' get current snap of employee table +2. In the employee management system menu, input '3' to add an employee +3. Input "IVE00001" for id (valid employee id) +4. Input "5" to check the average salary got updated + '''.strip(), + 'expected_output':''' +1. average salary changed from $19814.78 to $15135.64 (average of "5" employee) + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''add employee (cancelling)''', + 'procedure':''' +1. In the employee management system menu, input '2' to add an employee +2. Input "ENTER"(one key) for name (cancelling the add flow) + '''.strip(), + 'expected_output':''' +1. showing "***** Employee Add cancelled" +2. back to the main menu + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''add employee (cancelling)''', + 'procedure':''' +1. In the employee management system menu, input '2' to add an employee +2. Input "apple" for name (valid name) +3. Input "ENTER"(one key) for name (cancelling the add flow) + '''.strip(), + 'expected_output':''' +1. showing "Please input employee's name, Enter to return:" +2. after receiving valid name, showing "Please input employee's salary, Enter to return:" +3. after pressing "ENTER"(one key), showing "***** Employee Add cancelled" +4. back to the main menu + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''add employee (cancelling)''', + 'procedure':''' +1. In the employee management system menu, input '2' to add an employee +2. Input "apple" for name (valid name) +3. Input "100" for salary (valid salary) +4. Input "ENTER"(one key) for department (cancelling the add flow) + '''.strip(), + 'expected_output':''' +1. showing "Please input employee's name, Enter to return:" +2. after receiving valid name, showing "Please input employee's salary, Enter to return:" +3. after receiving valid salary, showing "Please input employee's department, Enter to return:" +4. after pressing "ENTER"(one key), showing "***** Employee Add cancelled" +5. back to the main menu + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''remove employee (cancelling)''', + 'procedure':''' +1. In the employee management system menu, input '3' to remove an employee +2. Input "ENTER"(one key) for id (cancelling the remove flow) + '''.strip(), + 'expected_output':''' +1. showing "***** Employee remove cancelled" + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +{ + 'test_case_name':'''update employee (cancelling)''', + 'procedure':''' +1. In the employee management system menu, input '4' to update an employee +2. Input "ENTER"(one key) for id (cancelling the update flow) + '''.strip(), + 'expected_output':''' +1. showing "***** Employee update cancelled" + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + + +{ + 'test_case_name':'''update employee (cancelling)''', + 'procedure':''' +1. In the employee management system menu, input '4' to update an employee +2. Input "IVE00006" for name (valid name) +3. Input "ENTER"(one key) for salary (cancelling the update flow) + '''.strip(), + 'expected_output':''' +1. showing "Please input employee's id, Enter to return:" +1. showing "Please input employee's salary, Enter to return:" +1. after pressing "ENTER"(one key), +1. showing "***** Employee update cancelled" + ''', + 'screen_dump':"", + 'result':"Pass/ ~~Fail~~" +}, + +] + +i = 0 +with open('test_case_table.md','a+') as o: + o.truncate(0) + o.write(table_template.replace('{{{rows}}}', + '\n'.join(map(lambda x: row_template + .replace(' 1 ',str(cases.index(x)+1)) + .replace(' 2 ',x['test_case_name']) + .replace(' 3 ',x['procedure'].replace('\n','
')) + .replace(' 4 ',x['expected_output'].replace('\n','
')) + .replace(' 5 ',f''' + ![](./screenshots/test{str(cases.index(x)+1)}.png) + '''.replace('\n','
')) + .replace(' 6 ',x['result']) + ,cases)))) + + # D:\\\\_workspace\\daniel_jo_assignment_student\\screenshots\\test{str(cases.index(x)+1)}.png + diff --git a/ITP3915-programming-fundamentals/helloworld.py b/ITP3915-programming-fundamentals/helloworld.py new file mode 100644 index 0000000..4587ee1 --- /dev/null +++ b/ITP3915-programming-fundamentals/helloworld.py @@ -0,0 +1,5 @@ + + +def print_helloworld(): + print('print_helloworld') + \ No newline at end of file diff --git a/ITP3915-programming-fundamentals/lint.bat b/ITP3915-programming-fundamentals/lint.bat new file mode 100644 index 0000000..12a6f7f --- /dev/null +++ b/ITP3915-programming-fundamentals/lint.bat @@ -0,0 +1,2 @@ +python.exe -m pycodestyle --max-line-length=120 .\delivery\assignment_student.py +python.exe -m pycodestyle --max-line-length=120 .\original\assignment_student.py \ No newline at end of file diff --git a/ITP3915-programming-fundamentals/meta.md b/ITP3915-programming-fundamentals/meta.md new file mode 100644 index 0000000..718c534 --- /dev/null +++ b/ITP3915-programming-fundamentals/meta.md @@ -0,0 +1,142 @@ +--- +tags: [python, ITP3915] +--- + +# daniel_jo + +# Extracted + +## REQUIREMENT + +- This Employee Management System has 5 functions. + - Users are allowed to + - display all employee information, + - display company statistics, + - add and + - To add an employee record, user is required to input employee's name, salary and department. + - Employee ID should be auto generate follow along with the last employee's record ID + - remove an employee, + - To remove an employee record, user is required to input the employee's id + - update employee salary by specify employee's id + - To update an employee salary, user is required to input the employee's id and salary. + - All employee information should be displayed for user as a reference when user perform remove employee and update employee's salary action + - The list of all employee information is stored in a text file named "employee_list.txt" + +# CHECKLIST + +### DELIVERY + + - `• Well-commented source code.` + - SYSTEM IMPLEMENTATION + + - `• A test plan showing the evidence of testing.` + - validation of input + - error control + - Prepare a word document + - with a number of test cases + - showing different inputs for different situations + that your program may encounter and how your program responses to show the capability of your program. + + - `8. Submit all your works (in a zip file under the name of your student ID — e.g. 229999999.zip)` + + + - test case (doc) + +### NOTES: + +``` +9. +Each student will be required to conduct an assignment demonstration during laboratory class to show the system and walk through all the functions. +The date of the demonstration will be after the assignment submission and is to be confirmed later (It should be the next lab session just after the submission of assignment normally). Zero Marks will be given if students do not perform any assignment demonstration. +``` + +``` +https://books.agiliq.com/projects/essential-python-tools/en/latest/linters.html +``` + +4. Your programs must follow the style guide stated in PEP8 — Style Guide for Python Code published by python.org. https://www.python.org/dev/peps/pep-0008/. Marks may be deducted if the style guide is not followed. + +### Marks Distribution + +- System Implementation (70%) + - Validation on the input data and display appropriate error messages (20%) +- Test plan (10%) + +### error output + +``` +ERROR_ID_NOT_FOUND = 1 +ERROR_ID_MAILFORMED = 2 +ERROR_INPUT_NAME_SHOULD_NOT_CONTAIN_DIGIT = 3 +ERROR_INPUT_SALARY =4 +ERROR_INPUT_DEPARTMENT = 5 +ERROR_INPUT_ID = 6 +ERROR_MENU_INPUT_IS_NOT_DIGIT_ONLY = 7 +ERROR_MENU_INPUT_INVALID_FUNCTION_NUMBER = 8 +``` + +### test main menu + +### Test plan fields + +- ID +- Test Case Name +- Procedure +- Expected Output +- Screen Dump +- Result + +| ID | Test Case Name | Procedure | Expected Output | Screen Dump | Result | +| ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | -------------- | --------------- | ----------- | ------ | +| Display all employees in the system | 1. Start program.
2. input 1 for display all employee | +| All employees' information including their employee ID, name, salary and department should be displayed | +| ![](./screenshots/test1.png) | ![](./screenshots/test1.png) | Pass/ ~~Fail~~ | + +#### Main menu + +- []valid input + - []1,2,3,4,5 + - []display function + - []enter + - []exitting +- []invalid input + - []0, 6, $, ! + +#### Display all employee + +- []functional + +#### Add an employee + +- []valid input +- []invalid input + - []id not found + - []name invalid + - []salary invalid + - []department invalid +- functional + - cancelling + +#### Remove an employee + +- []valid input +- []invalid input +- []id not found +- []functional + - []cancelling + +#### Update employee salary + +- []valid input +- []invalid input +- []id not found +- []salary invalid +- []functional + - []cancelling + +#### Display company statistics + +- []functional + - []highest + - []lowest + - []average diff --git a/ITP3915-programming-fundamentals/original/Assignment to student.pdf b/ITP3915-programming-fundamentals/original/Assignment to student.pdf new file mode 100644 index 0000000..c39eeee Binary files /dev/null and b/ITP3915-programming-fundamentals/original/Assignment to student.pdf differ diff --git a/ITP3915-programming-fundamentals/original/assignment_student.py b/ITP3915-programming-fundamentals/original/assignment_student.py new file mode 100644 index 0000000..c5ea8cf --- /dev/null +++ b/ITP3915-programming-fundamentals/original/assignment_student.py @@ -0,0 +1,141 @@ +############################################### +# Imports used # +# You may import other libraries if necessary # +############################################### +import sys + + +################################################# +# Constants used # +# You may add other constants here if necessary # +################################################# + +# constant tuple named DEPARTMENT to store the department that can be selected when add +DEPARTMENT = ("HR","IT","Admin", "Finance") + + +# Function ID mapped with name +RETURN = "" +DISPLAY_ALL_EMPLOYEES = 1 +ADD_AN_EMPLOYEE = 2 +REMOVE_AN_EMPLOYEE = 3 +UPDATE_EMPLOYEE_SALARY = 4 +DISPLAY_STATISTICS = 5 + +# Other constants here + + + +################################################# +# Functions used # +# You may add other functions here if necessary # +################################################# + + +# write a function display_all_employees for menu item 1 to display all employees in system +def display_all_employees(list_dict_employees): + # complete your function here + # this function have no return value + + pass + +# write a function display_stat for menu item 5 to display company statistics in system +def display_stat(list_dict_employees): + # complete your function here + # this function have no return value + + + pass + + + +# write a function read_employee_from_file to read in employee’s information from file named "employee.txt" located in the same folder +def read_employee_from_file(): + list_dict_employees = list() + # complete your function here + # this function should return a list of dictionary contains all employee's information + + + + + + + + + # This static variable is for your development in early stage + # Zero marks will be given if you assigned the employee data by this static variable + """ + list_dict_employees = [ + {"ID": "IVE00001", "Name": "Kelvin Yip", "Salary" : 43210.5, "Department": "IT" }, + {"ID": "IVE00002", "Name": "Cow Leung", "Salary" : 32105.4, "Department": "Admin" }, + {"ID": "IVE00003", "Name": "Leung Pig Hung", "Salary" : 21054.3, "Department": "HR" }, + {"ID": "IVE00004", "Name": "Michael Fung", "Salary" : 10543.2, "Department": "Finance" }, + {"ID": "IVE00005", "Name": "Joe Yeung", "Salary" : 6543.2, "Department": "IT" }, + {"ID": "IVE00006", "Name": "Martin Kung", "Salary" : 5432.1, "Department": "Admin" } + ] + """ + return list_dict_employees + + +# You may implement other necessary functions here + + + + + + + +# Main function starts here +def main(): + + # Read employees record from file + list_dict_employees = read_employee_from_file() + + + # Welcome message + print("Welcome to Employee Management System.") + + # Main menu + while True: + print("=======================================") + print("Employee Management System Menu:") + print("No. | Function") + print("1 | Display all employee") + print("2 | Add an employee") + print("3 | Remove an employee") + print("4 | Update employee salary") + print("5 | Display company statistics") + input_function = input("Please input your choice. (1 – 5, Enter to exit): ") + + + # When user pressed enter - break + if input_function == RETURN: + break + + + # When user input 1 to display all employee + if input_function == DISPLAY_ALL_EMPLOYEES: + pass + + + + # When user input 3 to remove employee record + elif input_function == REMOVE_AN_EMPLOYEE: + pass + + + # When user input 4 to update an employee salary + elif input_function == UPDATE_EMPLOYEE_SALARY: + pass + + + + # When user input 5 to display company statistics + elif input_function == DISPLAY_STATISTICS: + pass + + + + +if __name__ == "__main__": + main() diff --git a/ITP3915-programming-fundamentals/original/employee_list.txt b/ITP3915-programming-fundamentals/original/employee_list.txt new file mode 100644 index 0000000..644b388 --- /dev/null +++ b/ITP3915-programming-fundamentals/original/employee_list.txt @@ -0,0 +1,13 @@ +# A list containing all the employee details in this system +# Comments and empty lines are ignored +# Details are in the following pattern +# Employee ID, Employee Name, Salary, Department + +IVE00001, Kelvin Yip, 43210.5, IT +IVE00002, Cow Leung, 32105.4, Admin +IVE00003, Leung Pig Hung, 21054.3, HR +IVE00004, Michael Fung, 10543.2, Finance +IVE00005, Joe Yeung, 6543.2, IT +IVE00006, Martin Kung, 5432.1, Admin + + diff --git a/ITP3915-programming-fundamentals/ref/Chap04 - while Loops.pptx b/ITP3915-programming-fundamentals/ref/Chap04 - while Loops.pptx new file mode 100644 index 0000000..432317e Binary files /dev/null and b/ITP3915-programming-fundamentals/ref/Chap04 - while Loops.pptx differ diff --git a/ITP3915-programming-fundamentals/ref/Chap05 - for Loops.pptx b/ITP3915-programming-fundamentals/ref/Chap05 - for Loops.pptx new file mode 100644 index 0000000..1343073 Binary files /dev/null and b/ITP3915-programming-fundamentals/ref/Chap05 - for Loops.pptx differ diff --git a/ITP3915-programming-fundamentals/ref/Chap06 - Functions.pptx b/ITP3915-programming-fundamentals/ref/Chap06 - Functions.pptx new file mode 100644 index 0000000..8d6d460 Binary files /dev/null and b/ITP3915-programming-fundamentals/ref/Chap06 - Functions.pptx differ diff --git a/ITP3915-programming-fundamentals/ref/Chap07 - List.pptx b/ITP3915-programming-fundamentals/ref/Chap07 - List.pptx new file mode 100644 index 0000000..d1df6c5 Binary files /dev/null and b/ITP3915-programming-fundamentals/ref/Chap07 - List.pptx differ diff --git a/ITP3915-programming-fundamentals/ref/Chap08 - Tuple and Dictionary.pptx b/ITP3915-programming-fundamentals/ref/Chap08 - Tuple and Dictionary.pptx new file mode 100644 index 0000000..a79a370 Binary files /dev/null and b/ITP3915-programming-fundamentals/ref/Chap08 - Tuple and Dictionary.pptx differ diff --git a/ITP3915-programming-fundamentals/ref/Chap09 - Namespace and Scope, Module, Package, Try Except Structure.pptx b/ITP3915-programming-fundamentals/ref/Chap09 - Namespace and Scope, Module, Package, Try Except Structure.pptx new file mode 100644 index 0000000..99ad0f3 Binary files /dev/null and b/ITP3915-programming-fundamentals/ref/Chap09 - Namespace and Scope, Module, Package, Try Except Structure.pptx differ diff --git a/ITP3915-programming-fundamentals/ref/Chap10 - File Handling, Regular Expression and Output Formatting.pptx b/ITP3915-programming-fundamentals/ref/Chap10 - File Handling, Regular Expression and Output Formatting.pptx new file mode 100644 index 0000000..4788b43 Binary files /dev/null and b/ITP3915-programming-fundamentals/ref/Chap10 - File Handling, Regular Expression and Output Formatting.pptx differ diff --git a/ITP3915-programming-fundamentals/screenshots/test.sh b/ITP3915-programming-fundamentals/screenshots/test.sh new file mode 100644 index 0000000..2a5c3c3 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test.sh @@ -0,0 +1,64 @@ +touch test1.png +touch test2.png +touch test3.png +touch test4.png +touch test5.png +touch test6.png +touch test7.png +touch test8.png +touch test9.png +touch test10.png +touch test11.png +touch test12.png +touch test13.png +touch test14.png +touch test15.png +touch test16.png +touch test17.png +touch test18.png +touch test19.png +touch test20.png +touch test21.png +touch test22.png +touch test23.png +touch test24.png +touch test25.png +touch test26.png +touch test27.png +touch test28.png +touch test29.png +touch test30.png +touch test31.png +touch test32.png +touch test33.png +touch test34.png +touch test35.png +touch test36.png +touch test37.png +touch test38.png +touch test39.png +touch test40.png +touch test41.png +touch test42.png +touch test43.png +touch test44.png +touch test45.png +touch test46.png +touch test47.png +touch test48.png +touch test49.png +touch test50.png +touch test51.png +touch test52.png +touch test53.png +touch test54.png +touch test55.png +touch test56.png +touch test57.png +touch test58.png +touch test59.png +touch test60.png +touch test61.png +touch test62.png +touch test63.png +touch test64.png \ No newline at end of file diff --git a/ITP3915-programming-fundamentals/screenshots/test1.png b/ITP3915-programming-fundamentals/screenshots/test1.png new file mode 100644 index 0000000..2e1086c --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96f445bba4746f629b290c6fffd318e7a5bb4d281a96b1425be81c0b7ee81698 +size 33246 diff --git a/ITP3915-programming-fundamentals/screenshots/test10.png b/ITP3915-programming-fundamentals/screenshots/test10.png new file mode 100644 index 0000000..9d544a8 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test10.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:677247803a82c7b537839301b8d2afcea4257d302d3668c4dd4edbf7f7f799df +size 31000 diff --git a/ITP3915-programming-fundamentals/screenshots/test11.png b/ITP3915-programming-fundamentals/screenshots/test11.png new file mode 100644 index 0000000..c261854 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test11.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a190866dace3ad1a86a7fa09022f90994dfc7aa6dabbe7f1f3ff3bb13ec83881 +size 31946 diff --git a/ITP3915-programming-fundamentals/screenshots/test12.png b/ITP3915-programming-fundamentals/screenshots/test12.png new file mode 100644 index 0000000..87d5873 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test12.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2155824b93a9fd0d9ad9b612236d18d8eea9c79b1ec56fee1b98e1facc8e9571 +size 40579 diff --git a/ITP3915-programming-fundamentals/screenshots/test13.png b/ITP3915-programming-fundamentals/screenshots/test13.png new file mode 100644 index 0000000..1bb2e27 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test13.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:82c0f9b4268952563d8cdd3e2ad9f6847dbaf580691c0f18aae363ec89fab77d +size 40474 diff --git a/ITP3915-programming-fundamentals/screenshots/test14.png b/ITP3915-programming-fundamentals/screenshots/test14.png new file mode 100644 index 0000000..fe3a78e --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test14.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7fabf5fa7fd07edc62fa0fc58ea39c4196a9d7a1e4a1e773b7333b3a086a8238 +size 40242 diff --git a/ITP3915-programming-fundamentals/screenshots/test15.png b/ITP3915-programming-fundamentals/screenshots/test15.png new file mode 100644 index 0000000..ab346ab --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test15.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fde502cb54c5e7f84aa81eb4dff4e4144909ba8f36873e6cd2136d664f46cc74 +size 40381 diff --git a/ITP3915-programming-fundamentals/screenshots/test16.png b/ITP3915-programming-fundamentals/screenshots/test16.png new file mode 100644 index 0000000..cb2be3b --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test16.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9d0f2b1c1c405c2ce30fb060675459f11c44ec9ba8503ace31612418e9e813d +size 40955 diff --git a/ITP3915-programming-fundamentals/screenshots/test17.png b/ITP3915-programming-fundamentals/screenshots/test17.png new file mode 100644 index 0000000..016fcd9 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test17.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea0af2c789c7045c5357a9581afed06e793472327c43073f2e245c54dd60c5db +size 43001 diff --git a/ITP3915-programming-fundamentals/screenshots/test18.png b/ITP3915-programming-fundamentals/screenshots/test18.png new file mode 100644 index 0000000..641e14e --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test18.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:def6b8d70ad095152f90a7adc742bc09d685e4330cdbf4c27f863da1c19c5c95 +size 52796 diff --git a/ITP3915-programming-fundamentals/screenshots/test19.png b/ITP3915-programming-fundamentals/screenshots/test19.png new file mode 100644 index 0000000..145971f --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test19.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b2bc66fcfdbe0d25de8872cd76821632cbf715685455b7c520c81ddc825e78e8 +size 52361 diff --git a/ITP3915-programming-fundamentals/screenshots/test2.png b/ITP3915-programming-fundamentals/screenshots/test2.png new file mode 100644 index 0000000..0121f13 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:94b1c736fe0bd54b9288ed3d7f79719206c71432248d1da8fe1a13acc8421cc7 +size 28369 diff --git a/ITP3915-programming-fundamentals/screenshots/test20.png b/ITP3915-programming-fundamentals/screenshots/test20.png new file mode 100644 index 0000000..034ddcb --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test20.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:be0d35e6ca1b5668c5104a80bb2022ea54c80b7d8b3e5d06fcc2e697061493f6 +size 52070 diff --git a/ITP3915-programming-fundamentals/screenshots/test21.png b/ITP3915-programming-fundamentals/screenshots/test21.png new file mode 100644 index 0000000..e4bb33f --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test21.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b18f7504a56d22f3fa4b6a5a77e8ab2356c77938e0f8519c43837a0ebd645bea +size 52183 diff --git a/ITP3915-programming-fundamentals/screenshots/test22.png b/ITP3915-programming-fundamentals/screenshots/test22.png new file mode 100644 index 0000000..b1a06ab --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test22.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a8b3dca2bc603140e3297f0aedb76724633e7b367c04e5330d81d27bbad30373 +size 52070 diff --git a/ITP3915-programming-fundamentals/screenshots/test23.png b/ITP3915-programming-fundamentals/screenshots/test23.png new file mode 100644 index 0000000..74f2d60 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test23.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb0294a56751fa2c5373bf7976fdee7670534d5095a9b43f14aed22ae2336e2f +size 52469 diff --git a/ITP3915-programming-fundamentals/screenshots/test24.png b/ITP3915-programming-fundamentals/screenshots/test24.png new file mode 100644 index 0000000..bb68f84 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test24.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ef9201ef53ef9e96e5d88bf0485990de41519509c8cdb87ffe97888b09603b1 +size 25035 diff --git a/ITP3915-programming-fundamentals/screenshots/test25.png b/ITP3915-programming-fundamentals/screenshots/test25.png new file mode 100644 index 0000000..987d58f --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test25.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e21f20a73474bb8d35a094ed39271917725e01ca847a424d56119ff99045d0c4 +size 26080 diff --git a/ITP3915-programming-fundamentals/screenshots/test26.png b/ITP3915-programming-fundamentals/screenshots/test26.png new file mode 100644 index 0000000..fd7fd15 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test26.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49aee129b2eb4e155e58b76ea169bb21821b6d73a97f2291c846a417290c5a86 +size 27856 diff --git a/ITP3915-programming-fundamentals/screenshots/test27.png b/ITP3915-programming-fundamentals/screenshots/test27.png new file mode 100644 index 0000000..fdba111 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test27.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57ccd2dba34b917993cc39bf43f072182f6f93030e1494a907c71cfc7868206f +size 35536 diff --git a/ITP3915-programming-fundamentals/screenshots/test28.png b/ITP3915-programming-fundamentals/screenshots/test28.png new file mode 100644 index 0000000..69e97b7 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test28.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:acf60b8eaf08024a72201dcf8b0ae626aad34421daf82a057b0312a7e564036e +size 35250 diff --git a/ITP3915-programming-fundamentals/screenshots/test29.png b/ITP3915-programming-fundamentals/screenshots/test29.png new file mode 100644 index 0000000..4f09ea0 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test29.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ebcdb402aa2aa024f192e60ad94c4056b7d0788b260c0059413a46b92aa6f514 +size 36807 diff --git a/ITP3915-programming-fundamentals/screenshots/test3.png b/ITP3915-programming-fundamentals/screenshots/test3.png new file mode 100644 index 0000000..74d3d1f --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test3.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9e246f60d29c63f0ce9bb79dd5f9abcefca6bd31c902dee39e09c69e0f1e424 +size 36366 diff --git a/ITP3915-programming-fundamentals/screenshots/test30.png b/ITP3915-programming-fundamentals/screenshots/test30.png new file mode 100644 index 0000000..257261c --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test30.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:191cb9bbef669f769643e7e2cce779c3af653148cc664fbce90cd28a316726fb +size 53708 diff --git a/ITP3915-programming-fundamentals/screenshots/test31.png b/ITP3915-programming-fundamentals/screenshots/test31.png new file mode 100644 index 0000000..ea3b42e --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test31.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a5f95475f0aa1bd90c06c37455fcff7c421236c23de44987950df25743d675e +size 55831 diff --git a/ITP3915-programming-fundamentals/screenshots/test32.png b/ITP3915-programming-fundamentals/screenshots/test32.png new file mode 100644 index 0000000..cf5bb77 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test32.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb037fec08a290a2d1b5cbffb09d981a901b72bc14c37783d08b25b25ce6db9e +size 55510 diff --git a/ITP3915-programming-fundamentals/screenshots/test33.png b/ITP3915-programming-fundamentals/screenshots/test33.png new file mode 100644 index 0000000..395db8a --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test33.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8eb287df0763118ab5840560fabc077639f0ce2b67e0465d278a2c9281aab9cd +size 53459 diff --git a/ITP3915-programming-fundamentals/screenshots/test4.png b/ITP3915-programming-fundamentals/screenshots/test4.png new file mode 100644 index 0000000..190c512 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test4.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e86246db640ccf55b63be7f031fd6b278ca05c8085c268d35f341c4963c7f49e +size 37355 diff --git a/ITP3915-programming-fundamentals/screenshots/test5.png b/ITP3915-programming-fundamentals/screenshots/test5.png new file mode 100644 index 0000000..f1c5329 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test5.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a6aa009b79d1c5a07162ed6dc975f5aafcb5b46a7109f9408aa96cad3fb9b6fa +size 37855 diff --git a/ITP3915-programming-fundamentals/screenshots/test6.png b/ITP3915-programming-fundamentals/screenshots/test6.png new file mode 100644 index 0000000..d0d7a98 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test6.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa17f77f152cfa484a4b96c138537a230af5e0868e4a2f417fa10daabcd47c57 +size 18657 diff --git a/ITP3915-programming-fundamentals/screenshots/test7.png b/ITP3915-programming-fundamentals/screenshots/test7.png new file mode 100644 index 0000000..6ebdaf9 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test7.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69de916f8db379322a28e34a4b2f1cdbb5737895d87cf94b0400515ac5ad9e2f +size 19919 diff --git a/ITP3915-programming-fundamentals/screenshots/test8.png b/ITP3915-programming-fundamentals/screenshots/test8.png new file mode 100644 index 0000000..8c4e3c1 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test8.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6da4c0ae554cddeaad8a0fbcebc907fc8962cf12503860b34617737465c358be +size 19980 diff --git a/ITP3915-programming-fundamentals/screenshots/test9.png b/ITP3915-programming-fundamentals/screenshots/test9.png new file mode 100644 index 0000000..40556b8 --- /dev/null +++ b/ITP3915-programming-fundamentals/screenshots/test9.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0996b237302b0bcf0983681132318eb5520f1b14da246a1d0f17ecefd509573b +size 39026 diff --git a/ITP3915-programming-fundamentals/test_case_table.md b/ITP3915-programming-fundamentals/test_case_table.md new file mode 100644 index 0000000..6700151 --- /dev/null +++ b/ITP3915-programming-fundamentals/test_case_table.md @@ -0,0 +1,31 @@ +| ID | Test Case Name | Procedure | Expected Output | Screen Dump | Result | +| --- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------- | -------------- | +| 1 | Display all employees in the system | 1. Start program.
2. input 1 for display all employee | All employees' information including their employee ID, name, salary and department should be displayed |
![](./screenshots/test1.png)
| Pass/ ~~Fail~~ | +| 2 | Add an employee with name "Pika Chiu, salary 15000 and wortks in IT department into the system | 1. In the employee management system menu, input '2' to add an employee
2. Input 'Pika Chiu' for employee's name Input "15000" for salary
3. Input "IT" for IT department | A success message "Employee Added Successfully" should be displayed |
![](./screenshots/test2.png)
| Pass/ ~~Fail~~ | +| 3 | Remove an employee with valid employee id | 1. In the employee management system menu, input '3' to Remove an employee
2. Input 'IVE00006' for employee's id | A success message "Employee Removed Successfully" should be displayed |
![](./screenshots/test3.png)
| Pass/ ~~Fail~~ | +| 4 | Update an employee with valid employee id | 1. In the employee management system menu, input '4' to Update an employee
2. Input 'IVE00005' for employee's id
3. Input '99999' for employee's salary | A success message "Employee Updated Successfully" should be displayed |
![](./screenshots/test4.png)
| Pass/ ~~Fail~~ | +| 5 | Display company statistics | 1. In the employee management system menu, input '5' to Update an employee |
1. a list of all employee information listed
2. total number of staff listed
3. staff with highest salary listed
4. staff with lowest salary listed
5. average salary listed
|
![](./screenshots/test5.png)
| Pass/ ~~Fail~~ | +| 6 | exiting system | 1. In the employee management system menu, input "ENTER"(enter key) to exit system |
1. system exit
|
![](./screenshots/test6.png)
| Pass/ ~~Fail~~ | +| 7 | main menu invalid input handling | 1. In the employee management system menu, input "~" to main menu |
1. screen showing "input digit contains non-int value, accepted values are 1,2,3,4,5" alert to user
|
![](./screenshots/test7.png)
| Pass/ ~~Fail~~ | +| 8 | main menu invalid input handling | 1. In the employee management system menu, input "a" to main menu |
1. screen showing "input digit contains non-int value, accepted values are 1,2,3,4,5" alert to user
|
![](./screenshots/test8.png)
| Pass/ ~~Fail~~ | +| 9 | Add an employee (invalid employee name) | 1. In the employee management system menu, input '2' to add an employee
2. Input 'a1' for employee's name (this is invalid name)
3. Input '123' for employee's name (this is invalid name)
4. Input '4a' for employee's name (this is valid name)
5. Input 'apple' for employee's name (this is valid name)
6. Input "99999" for salary
7. Input "IT" for IT department |
1. showing "ERROR: sorry but the employee name should not contain digit" alert to user
2. keep asking "Please input employee's name, Enter to return:" until valid name get
3. after getting apple as name, get back to normal employee adding flow
|
![](./screenshots/test9.png)
| Pass/ ~~Fail~~ | +| 10 | Add an employee (invalid employee salary) | 1. In the employee management system menu, input '2' to add an employee
2. Input 'apple' for employee's name (this is valid name)
3. Input "aaaaa" for salary (invalid input as contains text)
4. Input "11111" for salary (valid input)
5. Input "IT" for IT department |
1. showing "ERROR: Employee's salary contains non digit value" alert to user
2. keep asking "Please input employee's salary, Enter to return:" until valid salary get
3. after getting valid salary, get back to normal employee adding flow
|
![](./screenshots/test10.png)
| Pass/ ~~Fail~~ | +| 11 | Add an employee (invalid employee department) | 1. In the employee management system menu, input '2' to add an employee
2. Input 'apple' for employee's name (this is valid name)
3. Input "11111" for salary (valid input)
4. Input "Marketing" (invalid input)
5. Input "IT" (valid input) |
1. showing "ERROR: Not a valid department, the valid options are HR, IT, Admin, Finance" alert to user
2. keep asking "Please input employee's department, Enter to return:" until valid department get
3. after getting valid department, show "**\*** Employee Added Successfully"
|
![](./screenshots/test11.png)
| Pass/ ~~Fail~~ | +| 12 | Remove an employee (invalid employee id, not existing) | 1. In the employee management system menu, input '3' to remove an employee
2. Input 'IVE00007' for employee's id (this is invalid id, not exist)
2. Input "IVE00006" for employee's id (valid input, existing id) |
1. showing "ERROR: sorry but the input id not found" alert to user
2. keep asking "Please input employee's id, Enter to return:" until valid id get
3. after getting valid id, show "**\*** Employee Removed Successfully"
|
![](./screenshots/test12.png)
| Pass/ ~~Fail~~ | +| 13 | Remove an employee (invalid employee id, invalid format) | 1. In the employee management system menu, input '3' to remove an employee
2. Input 'III00007' for employee's id (this is invalid id, not exist)
2. Input "IVE00006" for employee's id (valid input, existing id) |
1. showing "ERROR: sorry but the input id not found" alert to user
2. keep asking "Please input employee's id, Enter to return:" until valid id get
3. after getting valid id, show "**\*** Employee Removed Successfully"
|
![](./screenshots/test13.png)
| Pass/ ~~Fail~~ | +| 14 | Remove an employee (invalid employee id, invalid format) | 1. In the employee management system menu, input '3' to remove an employee
2. Input 'a' for employee's id (this is invalid id)
2. Input "IVE00006" for employee's id (valid input, existing id) |
1. showing "ERROR: sorry but the input id not found" alert to user
2. keep asking "Please input employee's id, Enter to return:" until valid id get
3. after getting valid id, show "**\*** Employee Removed Successfully"
|
![](./screenshots/test14.png)
| Pass/ ~~Fail~~ | +| 15 | Remove an employee (invalid employee id, invalid format) | 1. In the employee management system menu, input '3' to remove an employee
2. Input '11111111' for employee's id (this is invalid id)
3. Input "IVE00006" for employee's id (valid input, existing id) |
1. showing "ERROR: sorry but the input id not found" alert to user
2. keep asking "Please input employee's id, Enter to return:" until valid id get
3. after getting valid id, show "**\*** Employee Removed Successfully"
|
![](./screenshots/test15.png)
| Pass/ ~~Fail~~ | +| 16 | Update an employee (invalid employee id, invalid format) | 1. In the employee management system menu, input '4' to update an employee
2. Input '1' for employee's id (this is invalid id)
3. Input "IVE00006" for employee's id (valid input, existing id)
4. Input "11111" for employee's id (valid input) |
1. showing "ERROR: sorry but the input id not found" alert to user
2. keep asking "Please input employee's id, Enter to return:" until valid id get
3. after getting valid id, get back to normal update employee flow
|
![](./screenshots/test16.png)
| Pass/ ~~Fail~~ | +| 17 | Update an employee (invalid salary) | 1. In the employee management system menu, input '4' to update an employee
2. Input "IVE00006" for employee's id (valid employee id, existing id)
3. Input "a" for salary (invalid input, salary cannot be non integer value)
4. Input "$" for salary (invalid input, salary cannot be non integer value)
5. Input "111" for salary (value input, integer value only) |
1. showing "ERROR: Employee's salary contains non digit value" alert to user
2. keep asking "Please input employee's salary, Enter to return:" until valid salary get
3. after getting valid salary, show "**\*** Employee Updated Successfully" to user
|
![](./screenshots/test17.png)
| Pass/ ~~Fail~~ | +| 18 | display highest salary | 1. In the employee management system menu, input '5' get current snap of employee table
2. In the employee management system menu, input '2' to add an employee
3. Input "highest_employee" for name (valid employee name)
4. Input "9999999" for salary (valid highest salary)
5. Input "IT" for department (valid department)
6. Input "5" to check the highest salary got updated |
1. showing "highest_employee" in staff name field with highest salary
|
![](./screenshots/test18.png)
| Pass/ ~~Fail~~ | +| 19 | display lowest salary | 1. In the employee management system menu, input '5' get current snap of employee table
2. In the employee management system menu, input '2' to add an employee
3. Input "lowest_employee" for name (valid employee name)
4. Input "10" for salary (valid lowest salary)
5. Input "IT" for department (valid department)
6. Input "5" to check the lowest salary got updated |
1. showing "lowest_employee" in staff name field with lowest salary
|
![](./screenshots/test19.png)
| Pass/ ~~Fail~~ | +| 20 | update statistics after adding user | 1. In the employee management system menu, input '5' get current snap of employee table
2. In the employee management system menu, input '2' to add an employee
3. Input "new_user" for name (valid employee name)
4. Input "10" for salary (valid high salary)
5. Input "IT" for department (valid department)
6. Input "5" to check the lowest salary got updated |
1. number of staff = "6" + "1" = "7"
|
![](./screenshots/test20.png)
| Pass/ ~~Fail~~ | +| 21 | update statistics after remove user | 1. In the employee management system menu, input '5' get current snap of employee table
2. In the employee management system menu, input '3' to remove an employee
3. Input "IVE00006" for id (valid employee id) |
1. number of staff = "6" - "1" = "5"
|
![](./screenshots/test21.png)
| Pass/ ~~Fail~~ | +| 22 | update average after adding user | 1. In the employee management system menu, input '5' get current snap of employee table
2. In the employee management system menu, input '2' to add an employee
3. Input "new_user" for name (valid employee name)
4. Input "10" for salary (valid high salary)
5. Input "IT" for department (valid department)
6. Input "5" to check the average salary got updated |
1. average salary changed from $19814.78 to $16,985.53 (average of "7" employee)
|
![](./screenshots/test22.png)
| Pass/ ~~Fail~~ | +| 23 | update average after remove user | 1. In the employee management system menu, input '5' get current snap of employee table
2. In the employee management system menu, input '3' to add an employee
3. Input "IVE00001" for id (valid employee id)
4. Input "5" to check the average salary got updated |
1. average salary changed from $19814.78 to $15135.64 (average of "5" employee)
|
![](./screenshots/test23.png)
| Pass/ ~~Fail~~ | +| 24 | add employee (cancelling) | 1. In the employee management system menu, input '2' to add an employee
2. Input "ENTER"(one key) for name (cancelling the add flow) |
1. showing "**\*** Employee Add cancelled"
2. back to the main menu
|
![](./screenshots/test24.png)
| Pass/ ~~Fail~~ | +| 25 | add employee (cancelling) | 1. In the employee management system menu, input '2' to add an employee
2. Input "apple" for name (valid name)
3. Input "ENTER"(one key) for name (cancelling the add flow) |
1. showing "Please input employee's name, Enter to return:"
2. after receiving valid name, showing "Please input employee's salary, Enter to return:"
3. after pressing "ENTER"(one key), showing "**\*** Employee Add cancelled"
4. back to the main menu
|
![](./screenshots/test25.png)
| Pass/ ~~Fail~~ | +| 26 | add employee (cancelling) | 1. In the employee management system menu, input '2' to add an employee
2. Input "apple" for name (valid name)
3. Input "100" for salary (valid salary)
4. Input "ENTER"(one key) for department (cancelling the add flow) |
1. showing "Please input employee's name, Enter to return:"
2. after receiving valid name, showing "Please input employee's salary, Enter to return:"
3. after receiving valid salary, showing "Please input employee's department, Enter to return:"
4. after pressing "ENTER"(one key), showing "**\*** Employee Add cancelled"
5. back to the main menu
|
![](./screenshots/test26.png)
| Pass/ ~~Fail~~ | +| 27 | remove employee (cancelling) | 1. In the employee management system menu, input '3' to remove an employee
2. Input "ENTER"(one key) for id (cancelling the remove flow) |
1. showing "**\*** Employee remove cancelled"
|
![](./screenshots/test27.png)
| Pass/ ~~Fail~~ | +| 28 | update employee (cancelling) | 1. In the employee management system menu, input '4' to update an employee
2. Input "ENTER"(one key) for id (cancelling the update flow) |
1. showing "**\*** Employee update cancelled"
|
![](./screenshots/test28.png)
| Pass/ ~~Fail~~ | +| 29 | update employee (cancelling) | 1. In the employee management system menu, input '4' to update an employee
2. Input "IVE00006" for name (valid name)
3. Input "ENTER"(one key) for salary (cancelling the update flow) |
1. showing "Please input employee's id, Enter to return:"
1. showing "Please input employee's salary, Enter to return:"
1. after pressing "ENTER"(one key),
1. showing "**\*** Employee update cancelled"
|
![](./screenshots/test29.png)
| Pass/ ~~Fail~~ | diff --git a/ITP4459_assignment_2023/.editorconfig b/ITP4459_assignment_2023/.editorconfig new file mode 100644 index 0000000..7d144ec --- /dev/null +++ b/ITP4459_assignment_2023/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = crlf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/ITP4459_assignment_2023/.gitignore b/ITP4459_assignment_2023/.gitignore new file mode 100644 index 0000000..d2f96d2 --- /dev/null +++ b/ITP4459_assignment_2023/.gitignore @@ -0,0 +1,181 @@ +**/__pycache__ + +*.del +**/volumes + +# Created by https://www.toptal.com/developers/gitignore/api/python +# Edit at https://www.toptal.com/developers/gitignore?templates=python + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +# End of https://www.toptal.com/developers/gitignore/api/python diff --git a/ITP4459_assignment_2023/docs/Additional Hints for assignment.docx b/ITP4459_assignment_2023/docs/Additional Hints for assignment.docx new file mode 100644 index 0000000..f8de0a0 Binary files /dev/null and b/ITP4459_assignment_2023/docs/Additional Hints for assignment.docx differ diff --git a/ITP4459_assignment_2023/docs/ITP4459_assignment_2023_student_20230329.docx b/ITP4459_assignment_2023/docs/ITP4459_assignment_2023_student_20230329.docx new file mode 100644 index 0000000..a00f599 Binary files /dev/null and b/ITP4459_assignment_2023/docs/ITP4459_assignment_2023_student_20230329.docx differ diff --git a/ITP4459_assignment_2023/docs/ITP4459_assignment_2023_student_20230329.pdf b/ITP4459_assignment_2023/docs/ITP4459_assignment_2023_student_20230329.pdf new file mode 100644 index 0000000..b87e072 Binary files /dev/null and b/ITP4459_assignment_2023/docs/ITP4459_assignment_2023_student_20230329.pdf differ diff --git a/ITP4459_assignment_2023/docs/gars.pdf b/ITP4459_assignment_2023/docs/gars.pdf new file mode 100644 index 0000000..423cb5d Binary files /dev/null and b/ITP4459_assignment_2023/docs/gars.pdf differ diff --git a/ITP4459_assignment_2023/meta.md b/ITP4459_assignment_2023/meta.md new file mode 100644 index 0000000..b17f062 --- /dev/null +++ b/ITP4459_assignment_2023/meta.md @@ -0,0 +1,5 @@ +--- +tags: [python, ITP4459] +--- + +# daniel_jo diff --git a/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/Pipfile b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/Pipfile new file mode 100644 index 0000000..86518b4 --- /dev/null +++ b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +mysql-connector-python = "*" +mysql = "*" + +[dev-packages] + +[requires] +python_version = "3.10" diff --git a/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/Pipfile.lock b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/Pipfile.lock new file mode 100644 index 0000000..6e6a409 --- /dev/null +++ b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/Pipfile.lock @@ -0,0 +1,101 @@ +{ + "_meta": { + "hash": { + "sha256": "0fd1d2effb4d8a2ed0a80b8b6f653916ad4787fb9b8cd7141b795ea33dabd868" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.10" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "mysql": { + "hashes": [ + "sha256:8893cb143a5ac525c49ef358a23b8a0dc9721a95646f7bab6ca2f384c18a6a9a", + "sha256:fd7bae7d7301ce7cd3932e5ff7f77bbc8e34872108252866e08d16d6b8e8de8c" + ], + "index": "pypi", + "version": "==0.0.3" + }, + "mysql-connector-python": { + "hashes": [ + "sha256:145aeb75eefb7425e0a7fb36a4f95ebfe79e06be7c69a4045d34cde95c666dc4", + "sha256:1c0a11f3ffbf850f2ca7b39e6c82021e8de910ddaeffd856e53dca028d21c923", + "sha256:1f399f3c2599d2591854cd0e0a24c7c399dff21ac5accb6e52e06924de29f3f4", + "sha256:232095f0c36266510009b0f1214d2823a649efb8bc511dbab9ce8847f66ab08a", + "sha256:283fe6f647e9d684feb1b7c48fa6a46b1e72c59ecdd6ea2b62392cd80c1a6701", + "sha256:4b2d00c9e2cb9e3d11c57ec411226f43aa627607085fbed661cfea1c4dc57f61", + "sha256:4df11c683924ef34c177a54887dc4844ae735b01c8a29ce6ab92d6d3db7a2757", + "sha256:677b5c6dcaec7e2a4bf95b991a869f4d371114f69a0d9a5bb236e988c8f4c376", + "sha256:6cdba2779bcd16af0ceff0a6e50d33e6664a83f8d17d70524beb6f677a6d1fae", + "sha256:7f7a69db9e0c36764a6c65377f6174aee46e484520e48659e7aa674415b8e192", + "sha256:8c334c41cd1c5bcfa3550340253ef7d9d3b962211f33327c20f69706a0bcce06", + "sha256:8c5bfedc979d7858402f39c20d66a6cf03ca4c960732a98318126c278535ddb2", + "sha256:93b1eb3e07d19a23ccf2605d818aacee0d842b1820bbeef8d0022d8d3d014ab9", + "sha256:992b7a464daa398e86df8c75f7d8cd6044f884ff9087e782120fc8beff96c638", + "sha256:ab13dd6ede0e0e99ba97c73946462c3420625ab6e63fe13b6fc350e30eb3298d", + "sha256:bd52a462759aa324a60054c4b44dc8b32007187a328f72be6b58f193d5e32a91", + "sha256:bdd716b1e162fe4b3887f6617e9ddcfa659ba96a9ddb22feeae208a72f43d22f", + "sha256:be82357cc7e7e1377e2f4f8c18aa89c8aab6c0117155cf9fcf18e3cd0eb6ac8e", + "sha256:c2d20b29fd096a0633f9360c275bd2434d4bcf597281991c4b7f1c820cd07b84", + "sha256:c8bba02501525e1fbbba094a6d8d391d1534e8be41be6396c3e1b9f7d9d13b1c", + "sha256:c990f4c0702d1739076261c4dece1042e1eb18bf34e0d8516d19ec5166a205ce", + "sha256:d6b54656ca131a4f0f17b9d0adddc60f84fd982d64e06360026d5b06e5dbf865", + "sha256:e0299236297b63bf6cbb61d81a9d400bc01cad4743d1abe5296ef349de15ee53", + "sha256:e722b6ffa5b0d7188eebac792b18bc871643db505bf60d0e6bd2859f31e5ed79", + "sha256:fd233c83daaf048c1f9827be984c2721576ae0adf50e139429a06ccd094987d9" + ], + "index": "pypi", + "version": "==8.0.32" + }, + "mysqlclient": { + "hashes": [ + "sha256:0d1cd3a5a4d28c222fa199002810e8146cffd821410b67851af4cc80aeccd97c", + "sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782", + "sha256:996924f3483fd36a34a5812210c69e71dea5a3d5978d01199b78b7f6d485c855", + "sha256:b355c8b5a7d58f2e909acdbb050858390ee1b0e13672ae759e5e784110022994", + "sha256:c1ed71bd6244993b526113cca3df66428609f90e4652f37eb51c33496d478b37", + "sha256:c812b67e90082a840efb82a8978369e6e69fc62ce1bda4ca8f3084a9d862308b", + "sha256:dea88c8d3f5a5d9293dfe7f087c16dd350ceb175f2f6631c9cf4caf3e19b7a96" + ], + "markers": "python_version >= '3.5'", + "version": "==2.1.1" + }, + "protobuf": { + "hashes": [ + "sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7", + "sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c", + "sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2", + "sha256:398a9e0c3eaceb34ec1aee71894ca3299605fa8e761544934378bbc6c97de23b", + "sha256:44246bab5dd4b7fbd3c0c80b6f16686808fab0e4aca819ade6e8d294a29c7050", + "sha256:447d43819997825d4e71bf5769d869b968ce96848b6479397e29fc24c4a5dfe9", + "sha256:67a3598f0a2dcbc58d02dd1928544e7d88f764b47d4a286202913f0b2801c2e7", + "sha256:74480f79a023f90dc6e18febbf7b8bac7508420f2006fabd512013c0c238f454", + "sha256:819559cafa1a373b7096a482b504ae8a857c89593cf3a25af743ac9ecbd23480", + "sha256:899dc660cd599d7352d6f10d83c95df430a38b410c1b66b407a6b29265d66469", + "sha256:8c0c984a1b8fef4086329ff8dd19ac77576b384079247c770f29cc8ce3afa06c", + "sha256:9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e", + "sha256:a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db", + "sha256:b6cc7ba72a8850621bfec987cb72623e703b7fe2b9127a161ce61e61558ad905", + "sha256:bf01b5720be110540be4286e791db73f84a2b721072a3711efff6c324cdf074b", + "sha256:c02ce36ec760252242a33967d51c289fd0e1c0e6e5cc9397e2279177716add86", + "sha256:d9e4432ff660d67d775c66ac42a67cf2453c27cb4d738fc22cb53b5d84c135d4", + "sha256:daa564862dd0d39c00f8086f88700fdbe8bc717e993a21e90711acfed02f2402", + "sha256:de78575669dddf6099a8a0f46a27e82a1783c557ccc38ee620ed8cc96d3be7d7", + "sha256:e64857f395505ebf3d2569935506ae0dfc4a15cb80dc25261176c784662cdcc4", + "sha256:f4bd856d702e5b0d96a00ec6b307b0f51c1982c2bf9c0052cf9019e9a544ba99", + "sha256:f4c42102bc82a51108e449cbb32b19b180022941c727bac0cfd50170341f16ee" + ], + "markers": "python_version >= '3.7'", + "version": "==3.20.3" + } + }, + "develop": {} +} diff --git a/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/app.py b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/app.py new file mode 100644 index 0000000..07c59cc --- /dev/null +++ b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/app.py @@ -0,0 +1,116 @@ +import tkinter +import tkinter.ttk + +import constants +from models import Programme +from widgets import ModuleWidget + +# app.py - Main GUI dialog +# TODO: Remove all 'pass' statements and complete the implementation based on class description + +class App(tkinter.Tk): + def __init__(self, db): + super().__init__() + self.__db = db + self.refresh_db() + + self.__programme = None + self.__modules = None + self.setup_ui() + + # NOTE: Do not modify this method + def report_callback_exception(self, *args): + """When an error is occurred, raise the exception + so main_gui.py will handle the display of error. + """ + raise args[1].with_traceback(args[2]) + + def refresh_db(self): + # TODO: Fetch all program records from database, and store it in __programme as a list + pass + + def setup_ui(self): + self.title(constants.APP_NAME) + self.minsize(640, 480) + + # Set weight of column 0 for auto resizing on X axis + self.columnconfigure(0, weight=1) + + # Header + frm_top_bar = tkinter.Frame(self) + frm_top_bar.grid(row=0, sticky=tkinter.EW) + tkinter.Label( + frm_top_bar, + text = constants.APP_NAME, + font = ('bold', 16) + ).pack(side = tkinter.LEFT, padx=8, pady=8) + tkinter.ttk.Separator(self).grid(row=1, sticky=tkinter.EW) + + # Content + frm_content = tkinter.Frame(self) + frm_content.grid(row=2, sticky=tkinter.NSEW) + self.rowconfigure(2, weight=1) + + # Options + frm_filter = tkinter.LabelFrame(frm_content, text = "Options") + frm_filter.pack(fill=tkinter.X, side=tkinter.TOP, padx=8, pady=(4, 0)) + frm_filter_container = tkinter.Frame(frm_filter) + frm_filter_container.pack(fill=tkinter.BOTH, side=tkinter.TOP, padx=6, pady=(0, 4)) + + # Options variables + # TODO: Implement tkinter.StringVar for the widgets in 'Options' + + # Option widgets + tkinter.Label( + frm_filter_container, + text = "Programme", + ).grid(row=0, column=0, padx=(0, 4), sticky=tkinter.W) + # TODO: Implement tkinter.OptionMenu __om_programme_filter + options_list = ["follow methods inside assignment", "follow methods inside assignment 2", "follow methods inside assignment 3", "follow methods inside assignment 4"] + value_inside = tkinter.StringVar(frm_filter_container) + question_menu = tkinter.ttk.OptionMenu(frm_filter_container, value_inside, *options_list) + question_menu.grid(row=0, column=1, padx=(0, 4), sticky=tkinter.W) + print(question_menu["menu"].keys()) + + # Semester select + tkinter.Label( + frm_filter_container, + text = "Semester", + ).grid(row=0, column=2, padx=(4, 4), sticky=tkinter.W) + # TODO: Implement tkinter.OptionMenu __om_semester_filter + + # Modules + frm_modules = tkinter.LabelFrame(frm_content, text = "Modules") + frm_modules.pack(fill=tkinter.BOTH, side=tkinter.TOP, expand=1, padx=8, pady=(4, 0)) + self.__frm_modules_container = tkinter.Frame(frm_modules) + self.__frm_modules_container.pack(fill=tkinter.BOTH, side=tkinter.TOP, padx=6, pady=(0, 4)) + + self.__module_widgets = list() + for _ in range(constants.APP_MAX_MODULES): + widget = ModuleWidget(self.__frm_modules_container, self.on_gpa_changed) + widget.get_frame().pack(fill=tkinter.X, side=tkinter.TOP, expand=1, pady=8) + self.__module_widgets.append(widget) + + # Bottom bar + frm_bottom_bar = tkinter.Frame(self) + frm_bottom_bar.grid(row=3, sticky=tkinter.EW) + + # Result Label + # TODO: Implement tkinter.Label __lbl_result + + def setup_module_list(self): + # TODO: Update the ModuleWidget in list __module_widgets to display + # modules for the selected programme and semester + pass + + def on_programme_changed(self, _): + # TODO: Get selected programme based on option menu index, and update GUI + pass + + def on_semester_changed(self, _): + # TODO: Get modules based on option menu value, and update GUI + pass + + def on_gpa_changed(self): + # TODO: Calcuate semester GPA based on self.__modules + pass diff --git a/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/constants.py b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/constants.py new file mode 100644 index 0000000..c9bedbf --- /dev/null +++ b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/constants.py @@ -0,0 +1,28 @@ +# Database +# TODO: Modify the username and password if needed +DB_HOST = "localhost" + +# TODO: fallback root password +DB_USER = "db_user" +DB_PASS = "db_user_pass" + +DB_NAME = "itp4459_asg" + +# Tkinter GUI +APP_NAME = "GPA Calculator" +APP_MAX_MODULES = 7 + +# Application logic +GPA_MAPPING = { + "A": 4, + "A-": 3.7, + "B+": 3.3, + "B": 3, + "B-": 2.7, + "C+": 2.3, + "C": 2, + "C-": 1.7, + "D+": 1.3, + "D": 1, + "F": 0 +} diff --git a/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/db.py b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/db.py new file mode 100644 index 0000000..c4d5336 --- /dev/null +++ b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/db.py @@ -0,0 +1,78 @@ +from abc import ABC, abstractmethod + +import mysql.connector + +# db.py - Database related classes +# NOTE: You do not need to modify this source file + +__all__ = ( + 'MySQLConnection', 'MySQLObject' +) + +class MySQLConnection: + """A class to handle all database related functions for this assingment.""" + + def __init__(self, host, user, password, database=None): + """Initialize connection to MySQL server. + + Create database if needed automatically. + """ + self.db = mysql.connector.connect( + host=host, + user=user, + password=password + ) + if database is not None: + with self.db.cursor() as cursor: + cursor.execute(f"CREATE DATABASE IF NOT EXISTS {database};") + self.db.commit() + self.db.database = database + + def close(self): + """Closes the database connection.""" + self.db.close() + + def cursor(self): + """Returns a database cursor, for executing multiple statments + in a single transaction. + """ + return self.db.cursor() + + def commit(self): + """Commit changes to database.""" + self.db.commit() + + def execute(self, query): + """Commit: Python -> Database + + e.g. CREATE, INSERT and UPDATE + """ + with self.db.cursor() as cursor: + cursor.execute(query) + self.db.commit() + + def fetchone(self, query): + """Fetch: Python <- Database + + e.g. SELECT and SHOW + """ + with self.db.cursor() as cursor: + cursor.execute(query) + return cursor.fetchone() + + def fetchall(self, query): + """Fetch: Python <- Database + + e.g. SELECT and SHOW + """ + with self.db.cursor() as cursor: + cursor.execute(query) + return cursor.fetchall() + +class MySQLObject(ABC): + """A database managed object.""" + @staticmethod + @abstractmethod + def fetchall(db): + """Returns a list of object imported from database.""" + return NotImplemented diff --git a/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/main_db.py b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/main_db.py new file mode 100644 index 0000000..5fd1f3c --- /dev/null +++ b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/main_db.py @@ -0,0 +1,25 @@ +import constants +from db import MySQLConnection + +# main_db.py - Program entry point for Part 1 Database + +if __name__ == "__main__": + db = MySQLConnection( + host=constants.DB_HOST, + user=constants.DB_USER, + password=constants.DB_PASS + ) + with db.cursor() as cursor: + # Recreate database and select as default + cursor.execute(f"DROP DATABASE IF EXISTS {constants.DB_NAME};") + cursor.execute(f"CREATE DATABASE {constants.DB_NAME};") + cursor.execute(f"USE {constants.DB_NAME};") + + # Tables + # TODO: Create tables according to the database description + + # Records + # TODO: Insert records according to the database description + + db.commit() + db.close() diff --git a/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/main_gui.py b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/main_gui.py new file mode 100644 index 0000000..0d08660 --- /dev/null +++ b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/main_gui.py @@ -0,0 +1,42 @@ +from tkinter import messagebox + +import constants +import traceback +from app import App +from db import MySQLConnection + +# main_gui.py - Program entry point for Part 2 GUI +# NOTE: You do not need to modify this source file + +if __name__ == "__main__": + app = None + db = None + try: + # Create connection to database + db = MySQLConnection( + host=constants.DB_HOST, + user=constants.DB_USER, + password=constants.DB_PASS, + database=constants.DB_NAME) + + # Create and start app + app = App(db) + app.mainloop() + except Exception as e: + # Display error in console + traceback.print_exception(e) + + # Display error as message box + errorType = f"{type(e).__name__}" + messagebox.showerror(errorType, e.__str__()) + + # Close the app window + if app is App: + app.destroy() + + # Raise the error again for debugger + raise e + finally: + # Close database connection + if db is MySQLConnection: + db.close() diff --git a/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/models.py b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/models.py new file mode 100644 index 0000000..26b05a9 --- /dev/null +++ b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/models.py @@ -0,0 +1,10 @@ +from db import MySQLObject + +# models.py - Python representation of database table records +# TODO: Remove all 'pass' statements and complete the implementation based on class description + +class Programme(MySQLObject): + pass + +class Module(MySQLObject): + pass diff --git a/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/run.bat b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/run.bat new file mode 100644 index 0000000..272a3d6 --- /dev/null +++ b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/run.bat @@ -0,0 +1,14 @@ +@REM feed +@REM python ./src/main_db.py + +@REM pip install mysql-connector-python-rf + +python ./main_gui.py + +@REM python ./src/test_combobox.py + +@REM python .\src\options_test.py +@REM pipenv run ".\src\models.py" + +@REM pipenv run ".\src\test_models.py" + diff --git a/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/widgets.py b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/widgets.py new file mode 100644 index 0000000..b7c110b --- /dev/null +++ b/ITP4459_assignment_2023/notes/Assignment2223_student_v2_original/widgets.py @@ -0,0 +1,53 @@ +import tkinter + +from constants import GPA_MAPPING + +# widgets.py - Implements a custom GUI widget 'ModuleWidget' +# TODO: Remove all 'pass' statements and complete the implementation based on class description + +class ModuleWidget: + """A supplier class for displaying a module and returning the GPA value. + """ + def __init__(self, master, command): + self.__module = None + self.__command = command + self.__gpa = -1 + + self.setup_ui(master) + self.set_module(self.__module) + + def set_module(self, module = None): + # TODO: When module is provided: + # - Update UI to display module information + # - Enable option menu + # Else + # - Clear entry content + # - Disable option menu + # Finally, update self.__module + pass + + def get_frame(self): + return self.__frame + + def get_gpa(self): + return self.__gpa + + def setup_ui(self, master): + # Variables + # TODO: Implement tkinter.StringVar for the widgets in this class + + # Contianer + self.__frame = tkinter.Frame(master) + + # Module name + # TODO: Implement tkinter.Entry __ent_name + + # Module credit + # TODO: Implement tkinter.Entry __ent_credit + + # Grade + # TODO: Implement tkinter.OptionMenu __om_grade + + def on_grade_changed(self, _): + # TODO: Get GPA based on combo box value + pass diff --git a/ITP4459_assignment_2023/notes/Chap01 - Object and Class.pptx b/ITP4459_assignment_2023/notes/Chap01 - Object and Class.pptx new file mode 100644 index 0000000..280d023 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Chap01 - Object and Class.pptx differ diff --git a/ITP4459_assignment_2023/notes/Chap02 - Initializer.pptx b/ITP4459_assignment_2023/notes/Chap02 - Initializer.pptx new file mode 100644 index 0000000..1b5bc8b Binary files /dev/null and b/ITP4459_assignment_2023/notes/Chap02 - Initializer.pptx differ diff --git a/ITP4459_assignment_2023/notes/Chap03 - Instance and Static Members.pptx b/ITP4459_assignment_2023/notes/Chap03 - Instance and Static Members.pptx new file mode 100644 index 0000000..8e9134b Binary files /dev/null and b/ITP4459_assignment_2023/notes/Chap03 - Instance and Static Members.pptx differ diff --git a/ITP4459_assignment_2023/notes/Chap04 - Inheritance and Overriding.pptx b/ITP4459_assignment_2023/notes/Chap04 - Inheritance and Overriding.pptx new file mode 100644 index 0000000..801607f Binary files /dev/null and b/ITP4459_assignment_2023/notes/Chap04 - Inheritance and Overriding.pptx differ diff --git a/ITP4459_assignment_2023/notes/Chap05 - Abstract Base Classes.pptx b/ITP4459_assignment_2023/notes/Chap05 - Abstract Base Classes.pptx new file mode 100644 index 0000000..b6394bd Binary files /dev/null and b/ITP4459_assignment_2023/notes/Chap05 - Abstract Base Classes.pptx differ diff --git a/ITP4459_assignment_2023/notes/Chap06 - Database Connection.pptx b/ITP4459_assignment_2023/notes/Chap06 - Database Connection.pptx new file mode 100644 index 0000000..899b0e5 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Chap06 - Database Connection.pptx differ diff --git a/ITP4459_assignment_2023/notes/Chap07a - Tkinter Part 1.pptx b/ITP4459_assignment_2023/notes/Chap07a - Tkinter Part 1.pptx new file mode 100644 index 0000000..fe7d6a3 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Chap07a - Tkinter Part 1.pptx differ diff --git a/ITP4459_assignment_2023/notes/Chap07b - Tkinter Part 2.pptx b/ITP4459_assignment_2023/notes/Chap07b - Tkinter Part 2.pptx new file mode 100644 index 0000000..f503f9f Binary files /dev/null and b/ITP4459_assignment_2023/notes/Chap07b - Tkinter Part 2.pptx differ diff --git a/ITP4459_assignment_2023/notes/Chap08 - Web Scraping.pptx b/ITP4459_assignment_2023/notes/Chap08 - Web Scraping.pptx new file mode 100644 index 0000000..f98c3a4 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Chap08 - Web Scraping.pptx differ diff --git a/ITP4459_assignment_2023/notes/Chap09a - Python Web Framework.pptx b/ITP4459_assignment_2023/notes/Chap09a - Python Web Framework.pptx new file mode 100644 index 0000000..27e0b73 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Chap09a - Python Web Framework.pptx differ diff --git a/ITP4459_assignment_2023/notes/Chap09b - Python Web Framework.pptx b/ITP4459_assignment_2023/notes/Chap09b - Python Web Framework.pptx new file mode 100644 index 0000000..d110824 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Chap09b - Python Web Framework.pptx differ diff --git a/ITP4459_assignment_2023/notes/Lab_01a - Object and Class_Answers.docx b/ITP4459_assignment_2023/notes/Lab_01a - Object and Class_Answers.docx new file mode 100644 index 0000000..c1a4d82 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_01a - Object and Class_Answers.docx differ diff --git a/ITP4459_assignment_2023/notes/Lab_01b - Object and Class_Answers.docx b/ITP4459_assignment_2023/notes/Lab_01b - Object and Class_Answers.docx new file mode 100644 index 0000000..4a40fb9 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_01b - Object and Class_Answers.docx differ diff --git a/ITP4459_assignment_2023/notes/Lab_02a - Initializer_Answers.doc b/ITP4459_assignment_2023/notes/Lab_02a - Initializer_Answers.doc new file mode 100644 index 0000000..2ca98fb Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_02a - Initializer_Answers.doc differ diff --git a/ITP4459_assignment_2023/notes/Lab_02b - Initializer_Answers.doc b/ITP4459_assignment_2023/notes/Lab_02b - Initializer_Answers.doc new file mode 100644 index 0000000..be9a0fa Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_02b - Initializer_Answers.doc differ diff --git a/ITP4459_assignment_2023/notes/Lab_03a - Instance and Static Members_Answers.doc b/ITP4459_assignment_2023/notes/Lab_03a - Instance and Static Members_Answers.doc new file mode 100644 index 0000000..ee79762 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_03a - Instance and Static Members_Answers.doc differ diff --git a/ITP4459_assignment_2023/notes/Lab_04a - Inheritance and Overriding_Answers.doc b/ITP4459_assignment_2023/notes/Lab_04a - Inheritance and Overriding_Answers.doc new file mode 100644 index 0000000..25c1eeb Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_04a - Inheritance and Overriding_Answers.doc differ diff --git a/ITP4459_assignment_2023/notes/Lab_04b - Inheritance_Answers.doc b/ITP4459_assignment_2023/notes/Lab_04b - Inheritance_Answers.doc new file mode 100644 index 0000000..a6035d1 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_04b - Inheritance_Answers.doc differ diff --git a/ITP4459_assignment_2023/notes/Lab_05a - Abstract Class_Answers.doc b/ITP4459_assignment_2023/notes/Lab_05a - Abstract Class_Answers.doc new file mode 100644 index 0000000..ad92346 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_05a - Abstract Class_Answers.doc differ diff --git a/ITP4459_assignment_2023/notes/Lab_05b - Abstract Class_Answers.doc b/ITP4459_assignment_2023/notes/Lab_05b - Abstract Class_Answers.doc new file mode 100644 index 0000000..5e05ef9 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_05b - Abstract Class_Answers.doc differ diff --git a/ITP4459_assignment_2023/notes/Lab_06a - Database Connection_Answers.doc b/ITP4459_assignment_2023/notes/Lab_06a - Database Connection_Answers.doc new file mode 100644 index 0000000..96a805a Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_06a - Database Connection_Answers.doc differ diff --git a/ITP4459_assignment_2023/notes/Lab_07a - Tkinter_Answers.doc b/ITP4459_assignment_2023/notes/Lab_07a - Tkinter_Answers.doc new file mode 100644 index 0000000..bc4a117 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_07a - Tkinter_Answers.doc differ diff --git a/ITP4459_assignment_2023/notes/Lab_07b - Tkinter_Answers.doc b/ITP4459_assignment_2023/notes/Lab_07b - Tkinter_Answers.doc new file mode 100644 index 0000000..9afcedb Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_07b - Tkinter_Answers.doc differ diff --git a/ITP4459_assignment_2023/notes/Lab_08a - Web Scraping_Answers.doc b/ITP4459_assignment_2023/notes/Lab_08a - Web Scraping_Answers.doc new file mode 100644 index 0000000..f6e589b Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_08a - Web Scraping_Answers.doc differ diff --git a/ITP4459_assignment_2023/notes/Lab_09a - Python Web Framework_Answers.doc b/ITP4459_assignment_2023/notes/Lab_09a - Python Web Framework_Answers.doc new file mode 100644 index 0000000..40e5a21 Binary files /dev/null and b/ITP4459_assignment_2023/notes/Lab_09a - Python Web Framework_Answers.doc differ diff --git a/ITP4459_assignment_2023/package-lock.json b/ITP4459_assignment_2023/package-lock.json new file mode 100644 index 0000000..810b4aa --- /dev/null +++ b/ITP4459_assignment_2023/package-lock.json @@ -0,0 +1,587 @@ +{ + "name": "itp4459_assignment_2023", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "itp4459_assignment_2023", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "nodemon": "^2.0.22" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + } + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "requires": { + "semver": "~7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "requires": { + "nopt": "~1.0.10" + } + }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + } + } +} diff --git a/ITP4459_assignment_2023/package.json b/ITP4459_assignment_2023/package.json new file mode 100644 index 0000000..20f02ff --- /dev/null +++ b/ITP4459_assignment_2023/package.json @@ -0,0 +1,17 @@ +{ + "name": "itp4459_assignment_2023", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "gitUpdate": "git add . && git commit -m\"update daniel_jo,\" && git push", + "test": "python \"Assignment2223_student_v2/helloworld.py\"", + "dev": "nodemon --ext py --exec \"src/run.bat\"" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "nodemon": "^2.0.22" + } +} diff --git a/ITP4459_assignment_2023/quotation.md b/ITP4459_assignment_2023/quotation.md new file mode 100644 index 0000000..ffd3c08 --- /dev/null +++ b/ITP4459_assignment_2023/quotation.md @@ -0,0 +1,41 @@ +mysql + gui + python + test case => 600 + +Reference: + - no seeder + +Delivery: + 5.1 Test Plan showing the evidence of testing (refer to Test Plan Example for reference) + 5.2 Source code for the entire program, with adequate comments. + +Submittion: + Submit all your works in a single ZIP file under the name of your student ID and name (e.g., 22XXXXXXX-ChanDaiMan.zip) to Moodle before the assignment deadline. Marks will be deducted for late submissions (e.g., during program demonstration) or even score ZERO mark. + +Plagiarism + +linting: +Your source code must follow the coding standard stated in PEP 8 – Style Guide for Python +Code. Marks may be deducted if the coding standard is not followed. + + + +This assignment is to implement a GPA Calculator using Object Oriented Programming Techniques. +Your programming must be able to show concepts such as + - Abstraction, + - Encapsulation, + - Inheritance and + - Polymorphism. + +Your program must be able to do the following: + - Establish connection to MySQL database server and perform read / write function. + - Display a list of programmes, semesters and modules for a semester. + - Calculate the semester GPA based on user input. + +UI given. + +Things to do +This assignment is divided into two parts: Database and Tkinter GUI. +Study the provided supplier class MySQLConnection in the file db.py. All database related function +must be executed through this class. +Study the provided constants variables in the file constants.py. +TODO comments are included for your easy identification on the parts needed to be completed by +you. diff --git a/ITP4459_assignment_2023/src/docker/docker-compose.yml b/ITP4459_assignment_2023/src/docker/docker-compose.yml new file mode 100644 index 0000000..5dbc376 --- /dev/null +++ b/ITP4459_assignment_2023/src/docker/docker-compose.yml @@ -0,0 +1,34 @@ +services: + mysql: + image: mysql:latest + # container_name: db + restart: unless-stopped + + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: itp4459_asg + MYSQL_USER: db_user + MYSQL_PASSWORD: db_user_pass + ports: + - "3306:3306" + volumes: + - db:/var/lib/mysql + + phpmyadmin: + image: phpmyadmin/phpmyadmin + # container_name: pma + restart: unless-stopped + links: + - mysql + environment: + PMA_HOST: mysql + PMA_PORT: 3306 + PMA_ARBITRARY: 1 + PMA_USER: "root" + PMA_PASSWORD: "root" + + ports: + - 8081:80 + +volumes: + db: diff --git a/ITP4459_assignment_2023/src/python/Pipfile b/ITP4459_assignment_2023/src/python/Pipfile new file mode 100644 index 0000000..6d7f91f --- /dev/null +++ b/ITP4459_assignment_2023/src/python/Pipfile @@ -0,0 +1,16 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +mysql = "*" +mysql-connector-python = "*" +mistune = ">=0.7.1" +python-docx = ">=0.8.6" +sympy = ">=0.7.6.1" + +[dev-packages] + +[requires] +python_version = "3.10" diff --git a/ITP4459_assignment_2023/src/python/Pipfile.lock b/ITP4459_assignment_2023/src/python/Pipfile.lock new file mode 100644 index 0000000..aa6170d --- /dev/null +++ b/ITP4459_assignment_2023/src/python/Pipfile.lock @@ -0,0 +1,214 @@ +{ + "_meta": { + "hash": { + "sha256": "6fc14ab26679ecb3c73181a5c3e6daa6ec1d2ff80343097b892a649cd17e0574" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.10" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "lxml": { + "hashes": [ + "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7", + "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726", + "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03", + "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140", + "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a", + "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05", + "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03", + "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419", + "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4", + "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e", + "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67", + "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50", + "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894", + "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf", + "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947", + "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1", + "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd", + "sha256:3ab9fa9d6dc2a7f29d7affdf3edebf6ece6fb28a6d80b14c3b2fb9d39b9322c3", + "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92", + "sha256:4c8f293f14abc8fd3e8e01c5bd86e6ed0b6ef71936ded5bf10fe7a5efefbaca3", + "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457", + "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74", + "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf", + "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1", + "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4", + "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975", + "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5", + "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe", + "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7", + "sha256:6b418afe5df18233fc6b6093deb82a32895b6bb0b1155c2cdb05203f583053f1", + "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2", + "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409", + "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f", + "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f", + "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5", + "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24", + "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e", + "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4", + "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a", + "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c", + "sha256:8d0b4612b66ff5d62d03bcaa043bb018f74dfea51184e53f067e6fdcba4bd8de", + "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f", + "sha256:925073b2fe14ab9b87e73f9a5fde6ce6392da430f3004d8b72cc86f746f5163b", + "sha256:998c7c41910666d2976928c38ea96a70d1aa43be6fe502f21a651e17483a43c5", + "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7", + "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a", + "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c", + "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9", + "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e", + "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab", + "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941", + "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5", + "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45", + "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7", + "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892", + "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746", + "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c", + "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53", + "sha256:b64d891da92e232c36976c80ed7ebb383e3f148489796d8d31a5b6a677825efe", + "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184", + "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38", + "sha256:be7292c55101e22f2a3d4d8913944cbea71eea90792bf914add27454a13905df", + "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9", + "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b", + "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2", + "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0", + "sha256:d02a5399126a53492415d4906ab0ad0375a5456cc05c3fc0fc4ca11771745cda", + "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b", + "sha256:d5bf6545cd27aaa8a13033ce56354ed9e25ab0e4ac3b5392b763d8d04b08e0c5", + "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380", + "sha256:da248f93f0418a9e9d94b0080d7ebc407a9a5e6d0b57bb30db9b5cc28de1ad33", + "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8", + "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1", + "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889", + "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9", + "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f", + "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==4.9.2" + }, + "mistune": { + "hashes": [ + "sha256:0246113cb2492db875c6be56974a7c893333bf26cd92891c85f63151cee09d34", + "sha256:bad7f5d431886fcbaf5f758118ecff70d31f75231b34024a1341120340a65ce8" + ], + "index": "pypi", + "version": "==2.0.5" + }, + "mpmath": { + "hashes": [ + "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", + "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c" + ], + "version": "==1.3.0" + }, + "mysql": { + "hashes": [ + "sha256:8893cb143a5ac525c49ef358a23b8a0dc9721a95646f7bab6ca2f384c18a6a9a", + "sha256:fd7bae7d7301ce7cd3932e5ff7f77bbc8e34872108252866e08d16d6b8e8de8c" + ], + "index": "pypi", + "version": "==0.0.3" + }, + "mysql-connector-python": { + "hashes": [ + "sha256:0004426e964856148e1cde31e9b8be63ae3013715b048ff0f2ede69a6ddd36f7", + "sha256:016662c6252f2c5f47805d9168187be1316d0c1d7109f9fe668482c3d6e5711d", + "sha256:241483065ad062256985e082e3cbb3e7d1d6d2275cee17c66d22525b09096201", + "sha256:34d5c5f6ec7c1e75bf972def40d097138e097dc694e36dec89a5dd604ef7aada", + "sha256:37eace5b7eb676a41ff1edc5cf6ce4ae1c28406d1a6fe84941e6aa396d688195", + "sha256:3bedf8265fb31698e4144ca54e241e3386802c3a437745b1a536a74cbe7e4fb9", + "sha256:41db4452a99ee28494313eab1aa7749475d3e39bed7b24a0868aee45bd0d9c73", + "sha256:46ff8a10c13f39996d60f45c30cf2ea15e883bc71d58259ed2fea0a5a6fb93a3", + "sha256:4c82fb70f44f2469c0879434c1d8ee3162f56a40cc8f5ca1cc4d97f06c84cd43", + "sha256:7266d7b2550f9fe0cdcea1647aa6aade352e14095042b6a3921c9152cf8543e8", + "sha256:7318f416b9defe84b2bd025304bab62b68f8d8fcbe479af5593161eff12ef169", + "sha256:753d07fb39a67f7f35fe6e6a4fac12008287661de59f9d5c0bf4da3359d83eb8", + "sha256:96f7fb0ccfe96e6e478e5f0f034c99bda961b99ffa1c746cee39cfea45b0c04d", + "sha256:9775331fa60b5d5a6925781d77eee4384e2b54a12dea694ffdefd1cf1a9c0fdb", + "sha256:984f5649e6abee04461d6f52fbc77387d7137b8fd003c54bac66505006f17183", + "sha256:9f5eb33e29742c5f8ef23df2d3f0de0e46f4325e4324016e15aba7f8665a68c0", + "sha256:a632d7b0e569a46e6d44e6cd3f8db747995a787a081870697dbfd3ae18949339", + "sha256:af9feec311d8ea51261e1ef1f959a442708e30f0024d08d0fb537b07a1271634", + "sha256:c20a85a69af41d2d7d5cf52106f0b9473775819d189487c6ff3d3f3946931ca2", + "sha256:d8167868ebad8d78ba69babd028626e96a51365cab76edf735b2559731759b62", + "sha256:db422b19347c5d00e078dd64e281e5b1e5a19a2d972dc2d9733b136d79c34798", + "sha256:e853e12c00e3beabc581f4e039222708ee606fef80a3bac6b1f497ed89a31aea", + "sha256:ea05590cb972b114efa027c343b4b7110d8e8450493984ebfb9a651e27674636", + "sha256:f324233af7ec9fcb19c23096af27662459708c0465886cb017d78ff3f5b78b55", + "sha256:f403ff22d3514d08028590fef463d17dc107ac72ea27a49429614949d82fda40" + ], + "index": "pypi", + "version": "==8.0.33" + }, + "mysqlclient": { + "hashes": [ + "sha256:0d1cd3a5a4d28c222fa199002810e8146cffd821410b67851af4cc80aeccd97c", + "sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782", + "sha256:996924f3483fd36a34a5812210c69e71dea5a3d5978d01199b78b7f6d485c855", + "sha256:b355c8b5a7d58f2e909acdbb050858390ee1b0e13672ae759e5e784110022994", + "sha256:c1ed71bd6244993b526113cca3df66428609f90e4652f37eb51c33496d478b37", + "sha256:c812b67e90082a840efb82a8978369e6e69fc62ce1bda4ca8f3084a9d862308b", + "sha256:dea88c8d3f5a5d9293dfe7f087c16dd350ceb175f2f6631c9cf4caf3e19b7a96" + ], + "markers": "python_version >= '3.5'", + "version": "==2.1.1" + }, + "protobuf": { + "hashes": [ + "sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7", + "sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c", + "sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2", + "sha256:398a9e0c3eaceb34ec1aee71894ca3299605fa8e761544934378bbc6c97de23b", + "sha256:44246bab5dd4b7fbd3c0c80b6f16686808fab0e4aca819ade6e8d294a29c7050", + "sha256:447d43819997825d4e71bf5769d869b968ce96848b6479397e29fc24c4a5dfe9", + "sha256:67a3598f0a2dcbc58d02dd1928544e7d88f764b47d4a286202913f0b2801c2e7", + "sha256:74480f79a023f90dc6e18febbf7b8bac7508420f2006fabd512013c0c238f454", + "sha256:819559cafa1a373b7096a482b504ae8a857c89593cf3a25af743ac9ecbd23480", + "sha256:899dc660cd599d7352d6f10d83c95df430a38b410c1b66b407a6b29265d66469", + "sha256:8c0c984a1b8fef4086329ff8dd19ac77576b384079247c770f29cc8ce3afa06c", + "sha256:9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e", + "sha256:a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db", + "sha256:b6cc7ba72a8850621bfec987cb72623e703b7fe2b9127a161ce61e61558ad905", + "sha256:bf01b5720be110540be4286e791db73f84a2b721072a3711efff6c324cdf074b", + "sha256:c02ce36ec760252242a33967d51c289fd0e1c0e6e5cc9397e2279177716add86", + "sha256:d9e4432ff660d67d775c66ac42a67cf2453c27cb4d738fc22cb53b5d84c135d4", + "sha256:daa564862dd0d39c00f8086f88700fdbe8bc717e993a21e90711acfed02f2402", + "sha256:de78575669dddf6099a8a0f46a27e82a1783c557ccc38ee620ed8cc96d3be7d7", + "sha256:e64857f395505ebf3d2569935506ae0dfc4a15cb80dc25261176c784662cdcc4", + "sha256:f4bd856d702e5b0d96a00ec6b307b0f51c1982c2bf9c0052cf9019e9a544ba99", + "sha256:f4c42102bc82a51108e449cbb32b19b180022941c727bac0cfd50170341f16ee" + ], + "markers": "python_version >= '3.7'", + "version": "==3.20.3" + }, + "python-docx": { + "hashes": [ + "sha256:1105d233a0956dd8dd1e710d20b159e2d72ac3c301041b95f4d4ceb3e0ebebc4" + ], + "index": "pypi", + "version": "==0.8.11" + }, + "sympy": { + "hashes": [ + "sha256:938f984ee2b1e8eae8a07b884c8b7a1146010040fccddc6539c54f401c8f6fcf", + "sha256:e32380dce63cb7c0108ed525570092fd45168bdae2faa17e528221ef72e88658" + ], + "index": "pypi", + "version": "==1.11.1" + } + }, + "develop": {} +} diff --git a/ITP4459_assignment_2023/src/python/app.py b/ITP4459_assignment_2023/src/python/app.py new file mode 100644 index 0000000..bc63299 --- /dev/null +++ b/ITP4459_assignment_2023/src/python/app.py @@ -0,0 +1,190 @@ +import tkinter +import tkinter.ttk + +import constants +from models import Programme +from widgets import ModuleWidget + +from pprint import pprint + +# app.py - Main GUI dialog + +class App(tkinter.Tk): + def __init__(self, db): + super().__init__() + self.__db = db + + self.__programme = None + self.__modules = None + + self.refresh_db() + self.setup_ui() + + # NOTE: Do not modify this method + def report_callback_exception(self, *args): + """When an error is occurred, raise the exception + so main_gui.py will handle the display of error. + """ + raise args[1].with_traceback(args[2]) + + def refresh_db(self): + # Fetch all program records from database, and store it in __programme as a list + self.__programme = Programme.fetchall(self.__db) + + def setup_ui(self): + self.title(constants.APP_NAME) + self.minsize(640, 480) + + # Set weight of column 0 for auto resizing on X axis + self.columnconfigure(0, weight=1) + + # Header + frm_top_bar = tkinter.Frame(self) + frm_top_bar.grid(row=0, sticky=tkinter.EW) + tkinter.Label( + frm_top_bar, + text = constants.APP_NAME, + font = ('bold', 16) + ).pack(side = tkinter.LEFT, padx=8, pady=8) + tkinter.ttk.Separator(self).grid(row=1, sticky=tkinter.EW) + + # Content + frm_content = tkinter.Frame(self) + frm_content.grid(row=2, sticky=tkinter.NSEW) + self.rowconfigure(2, weight=1) + + # Options + frm_filter = tkinter.LabelFrame(frm_content, text = "Options") + frm_filter.pack(fill=tkinter.X, side=tkinter.TOP, padx=8, pady=(4, 0)) + frm_filter_container = tkinter.Frame(frm_filter) + frm_filter_container.pack(fill=tkinter.BOTH, side=tkinter.TOP, padx=6, pady=(0, 4)) + + # Options variables + # Option widgets + tkinter.Label(frm_filter_container,text = "Programme",).grid(row=0, column=0, padx=(0, 4)) + list_of_programme=[] + for p in self.__programme: + list_of_programme.append(p.get_name()) + + self.selected_programme = tkinter.StringVar() + self.__om_programme_filter = tkinter.ttk.Combobox(frm_filter_container,textvariable=self.selected_programme, width=50) + self.__om_programme_filter.set('Please select') + self.__om_programme_filter['values'] = list_of_programme + self.__om_programme_filter['state'] = 'readonly' + self.__om_programme_filter.grid(row=0, column=1, padx=(0, 4), sticky=tkinter.EW) + self.__om_programme_filter.bind('<>', self.on_programme_changed ) + + # Semester select + tkinter.Label( frm_filter_container, text = "Semester").grid(row=0, column=2, padx=(0, 4)) + self.selected_semester = tkinter.StringVar() + self.__om_semester_filter = tkinter.ttk.Combobox(frm_filter_container, textvariable=self.selected_semester) + self.__om_semester_filter.set('Please select') + self.__om_semester_filter['state'] = 'disabled' + self.__om_semester_filter.grid(row=0, column=3, padx=(4, 4)) + self.__om_semester_filter.bind('<>', self.on_semester_changed) + + # Modules + frm_modules = tkinter.LabelFrame(frm_content, text = "Modules") + frm_modules.pack(fill=tkinter.BOTH, side=tkinter.TOP, expand=1, padx=8, pady=(4, 0)) + self.__frm_modules_container = tkinter.Frame(frm_modules) + self.__frm_modules_container.pack(fill=tkinter.BOTH, side=tkinter.TOP, padx=6, pady=(0, 4)) + + self.__module_widgets = list() + for _ in range(constants.APP_MAX_MODULES): + widget = ModuleWidget(self.__frm_modules_container, self.on_gpa_changed) + widget.get_frame().pack(fill=tkinter.X, side=tkinter.TOP, expand=1, pady=8) + widget.set_module(None) + + self.__module_widgets.append(widget) + + # Bottom bar + frm_bottom_bar = tkinter.Frame(self) + frm_bottom_bar.grid(row=3, column=0,padx=(0, 10), pady=(4,4), sticky=tkinter.E) + + # Result Label + self.semester_gpa = tkinter.StringVar() + self.lbl_stu_list = tkinter.ttk.Label(frm_bottom_bar, text='Semester GPA: %.2f' % 0, font=("bold",11)) + self.lbl_stu_list.grid(row=0, column=0, sticky=tkinter.E) + + def setup_module_list(self): + # Update the ModuleWidget in list __module_widgets to display + # modules for the selected programme and semester + current_select_idx = self.__om_semester_filter.current() + selected_semester = list(sorted(self.__modules.keys()))[current_select_idx] + module_in_semester = self.__modules[selected_semester] + for widget in self.__frm_modules_container.winfo_children(): + widget.destroy() + + self.__module_widgets = list() + i = 0 + for _ in range(constants.APP_MAX_MODULES): + widget = ModuleWidget(self.__frm_modules_container, self.on_gpa_changed) + widget.get_frame().pack(fill=tkinter.X, side=tkinter.TOP, expand=1, pady=8) + if (i < len(module_in_semester)): + widget.set_module(module_in_semester[i]) + + self.__module_widgets.append(widget) + i = i + 1 + + def on_programme_changed(self, _): + # Get selected programme based on option menu index, and update GUI + for program in self.__programme: + if (self.selected_programme.get() == program.get_name()): + self.__om_semester_filter['values'] = sorted(program.get_modules().keys()) + self.__modules = program.get_modules() + break + self.__om_semester_filter['state'] = 'readonly' + + self.__om_semester_filter.set('Please select') + + for widget in self.__frm_modules_container.winfo_children(): + widget.destroy() + + self.__module_widgets = list() + for _ in range(constants.APP_MAX_MODULES): + widget = ModuleWidget(self.__frm_modules_container, self.on_gpa_changed) + widget.get_frame().pack(fill=tkinter.X, side=tkinter.TOP, expand=1, pady=8) + widget.set_module(None) + self.__module_widgets.append(widget) + + # reset gpa + self.lbl_stu_list.configure(text='Semester GPA: %.2f' % (0)) + + + def on_semester_changed(self, _): + # Get modules based on option menu value, and update GUI + self.setup_module_list() + + # reset gpa + self.lbl_stu_list.configure(text='Semester GPA: %.2f' % (0)) + + + def on_gpa_changed(self): + # Calcuate semester GPA based on self.__modules + + # 1. For each modules in self.__modules, App class + # 2. Obtain the module credit of current module and add it to the total credits + # 3. Calculate the module gpa by multiplying the current module gpa and module credit + # 4. Add the calculated module gpa to total module gpa + # 5. After all module gpa are calculated, divide the total module gpa by total credits + + total = 0 + current_select_idx = self.__om_semester_filter.current() + selected_semester = list(sorted(self.__modules.keys()))[current_select_idx] + module_in_semester = self.__modules[selected_semester] + number_of_modules = len(module_in_semester) + + should_update = True + all_credit = 0 + for i in range(0, number_of_modules): + gpa = self.__module_widgets[i].get_gpa() + if (gpa == -1): + # not selected + should_update = False + else: + credit =self.__module_widgets[i].get_module().get_credit() + all_credit = all_credit + credit + total = total + (gpa * credit) + + if should_update: + self.lbl_stu_list.configure(text='Semester GPA: %.2f' % (total / all_credit)) diff --git a/ITP4459_assignment_2023/src/python/constants.py b/ITP4459_assignment_2023/src/python/constants.py new file mode 100644 index 0000000..cacb7b5 --- /dev/null +++ b/ITP4459_assignment_2023/src/python/constants.py @@ -0,0 +1,26 @@ +# Database +# NOTE: Modify the username and password if needed +DB_HOST = "localhost" +DB_NAME = "itp4459_asg" + +DB_USER = "db_user" +DB_PASS = "db_user_pass" + +# Tkinter GUI +APP_NAME = "GPA Calculator" +APP_MAX_MODULES = 7 + +# Application logic +GPA_MAPPING = { + "A": 4, + "A-": 3.7, + "B+": 3.3, + "B": 3, + "B-": 2.7, + "C+": 2.3, + "C": 2, + "C-": 1.7, + "D+": 1.3, + "D": 1, + "F": 0 +} diff --git a/ITP4459_assignment_2023/src/python/db.py b/ITP4459_assignment_2023/src/python/db.py new file mode 100644 index 0000000..886d8bd --- /dev/null +++ b/ITP4459_assignment_2023/src/python/db.py @@ -0,0 +1,78 @@ +from abc import ABC, abstractmethod + +import mysql.connector + +# db.py - Database related classes +# NOTE: You do not need to modify this source file + +__all__ = ( + 'MySQLConnection', 'MySQLObject' +) + +class MySQLConnection: + """A class to handle all database related functions for this assingment.""" + + def __init__(self, host, user, password, database=None): + """Initialize connection to MySQL server. + + Create database if needed automatically. + """ + self.db = mysql.connector.connect( + host=host, + user=user, + password=password + ) + if database is not None: + with self.db.cursor() as cursor: + cursor.execute(f"CREATE DATABASE IF NOT EXISTS {database};") + self.db.commit() + self.db.database = database + + def close(self): + """Closes the database connection.""" + self.db.close() + + def cursor(self): + """Returns a database cursor, for executing multiple statments + in a single transaction. + """ + return self.db.cursor() + + def commit(self): + """Commit changes to database.""" + self.db.commit() + + def execute(self, query): + """Commit: Python -> Database + + e.g. CREATE, INSERT and UPDATE + """ + with self.db.cursor() as cursor: + cursor.execute(query) + self.db.commit() + + def fetchone(self, query): + """Fetch: Python <- Database + + e.g. SELECT and SHOW + """ + with self.db.cursor() as cursor: + cursor.execute(query) + return cursor.fetchone() + + def fetchall(self, query): + """Fetch: Python <- Database + + e.g. SELECT and SHOW + """ + with self.db.cursor() as cursor: + cursor.execute(query) + return cursor.fetchall() + +class MySQLObject(ABC): + """A database managed object.""" + @staticmethod + @abstractmethod + def fetchall(db): + """Returns a list of object imported from database.""" + return NotImplemented diff --git a/ITP4459_assignment_2023/src/python/main_db.py b/ITP4459_assignment_2023/src/python/main_db.py new file mode 100644 index 0000000..a11e93c --- /dev/null +++ b/ITP4459_assignment_2023/src/python/main_db.py @@ -0,0 +1,99 @@ +import constants +from db import MySQLConnection + +# main_db.py - Program entry point for Part 1 Database + +tbl_programme = """ + CREATE TABLE IF NOT EXISTS programmes ( + programme_id VARCHAR(9) NOT NULL, + programme_name VARCHAR(100) NOT NULL, + PRIMARY KEY (programme_id) + )""" + +tbl_module = """ + CREATE TABLE IF NOT EXISTS modules ( + module_id VARCHAR(7) NOT NULL, + module_name VARCHAR(100) NOT NULL, + module_credit INT, + PRIMARY KEY (module_id) + )""" + +tbl_mapping = """ + CREATE TABLE IF NOT EXISTS mappings ( + mapping_programme_id VARCHAR(9) NOT NULL, + mapping_semester INT NOT NULL, + mapping_module_id VARCHAR(7) NOT NULL, + PRIMARY KEY (mapping_programme_id, mapping_semester, mapping_module_id), + FOREIGN KEY (mapping_programme_id) REFERENCES programmes(programme_id), + FOREIGN KEY (mapping_module_id) REFERENCES modules(module_id) + )""" + +radius = (('circle', 1.0),('circle', 2.0),('circle', 3.0)) +query = "INSERT INTO circles (name, radius) VALUES (%s, %s)" + +insert_programmes = ( + ('IT114124', "Higher Diploma in AI and Smart Technology"), + ('IT114122', "Higher Diploma in Cybersecurity") +) +insert_programme_query = "INSERT INTO programmes (programme_id, programme_name) VALUES (%s, %s)" + +insert_modules = ( + ("LAN3100","English & Communication: Workplace Interaction","6"), + ("LAN3103","English & Communication: Workplace Correspondance","6"), + ("LAN4107","English & Communication: Reports","9"), + ("LAN4108","English & Communication: Persuasive Presentations","9"), + ("LAN4101","English & Communication: Promotional Materials","10"), + ("LAN3003","Vocational Chinese Communication: Putonghua Conversation and Reports","6"), + ("LAN4003","Vocational Chinese Communication: Putonghua Presentations, Administrative and Technical Text Writing","9") +) + +insert_modules_query = "INSERT INTO modules (module_id, module_name, module_credit) VALUES (%s, %s, %s)" + +insert_mappings = ( + ("IT114124","1","LAN3100"), + ("IT114124","1","LAN3103"), + ("IT114124","1","LAN3003"), + ("IT114124","2","LAN4107"), + ("IT114124","2","LAN4003"), + ("IT114124","4","LAN4108"), + ("IT114124","5","LAN4101"), + ("IT114122","1","LAN3100"), + ("IT114122","1","LAN3103"), + ("IT114122","1","LAN3003"), + ("IT114122","2","LAN4107"), + ("IT114122","2","LAN4003"), + ("IT114122","4","LAN4108"), + ("IT114122","5","LAN4101") +) + +insert_mappings_query = "INSERT INTO mappings (mapping_programme_id, mapping_semester, mapping_module_id) VALUES (%s, %s, %s)" + +if __name__ == "__main__": + db = MySQLConnection( + host=constants.DB_HOST, + user=constants.DB_USER, + password=constants.DB_PASS + ) + + with db.cursor() as cursor: + # Recreate database and select as default + cursor.execute(f"DROP DATABASE IF EXISTS {constants.DB_NAME};") + cursor.execute(f"CREATE DATABASE {constants.DB_NAME};") + cursor.execute(f"USE {constants.DB_NAME};") + + # Tables + cursor.execute(tbl_programme) + cursor.execute(tbl_module) + cursor.execute(tbl_mapping) + + # Records + # cursor.executemany(query, radius) + cursor.executemany(insert_programme_query, insert_programmes) + cursor.executemany(insert_modules_query, insert_modules) + cursor.executemany(insert_mappings_query, insert_mappings) + + db.commit() + db.close() + + + diff --git a/ITP4459_assignment_2023/src/python/main_gui.py b/ITP4459_assignment_2023/src/python/main_gui.py new file mode 100644 index 0000000..0d08660 --- /dev/null +++ b/ITP4459_assignment_2023/src/python/main_gui.py @@ -0,0 +1,42 @@ +from tkinter import messagebox + +import constants +import traceback +from app import App +from db import MySQLConnection + +# main_gui.py - Program entry point for Part 2 GUI +# NOTE: You do not need to modify this source file + +if __name__ == "__main__": + app = None + db = None + try: + # Create connection to database + db = MySQLConnection( + host=constants.DB_HOST, + user=constants.DB_USER, + password=constants.DB_PASS, + database=constants.DB_NAME) + + # Create and start app + app = App(db) + app.mainloop() + except Exception as e: + # Display error in console + traceback.print_exception(e) + + # Display error as message box + errorType = f"{type(e).__name__}" + messagebox.showerror(errorType, e.__str__()) + + # Close the app window + if app is App: + app.destroy() + + # Raise the error again for debugger + raise e + finally: + # Close database connection + if db is MySQLConnection: + db.close() diff --git a/ITP4459_assignment_2023/src/python/models.py b/ITP4459_assignment_2023/src/python/models.py new file mode 100644 index 0000000..bfd11ec --- /dev/null +++ b/ITP4459_assignment_2023/src/python/models.py @@ -0,0 +1,143 @@ +import constants +from db import MySQLObject + +# models.py - Python representation of database table records + +class Programme(MySQLObject): + def __init__(self, id, name): + # initialize the id, name and modules attributes. + self.__id = id # a non-public string to store the id of the programme. + self.__name = name # a non-public string so store the name of the programme. + self.__modules = {} # a non-public dictionary to store Module objects, grouped by semester. + + def __eq__(self, other): + # returns true if the id attribute is equal to the other object’s id attribute. + return self.__id == other.get_id() + + def get_id(self): + # returns the id for this programme. + return self.__id + + def get_name(self): + # returns the name for this programme. + return self.__name + + def get_modules(self): + # returns Module dictionary object which contains module list of all semesters + return self.__modules + + def add_module(self, semester, module): + # append module into list inside modules’ dictionary, + # using semester as key. + if semester in self.__modules: + # module already contain semester, fall to end of function to add module into semester + pass + else: + # If the semester key is not found in the dictionary, + # an empty list will be created to store the module object, init an empty semester list literally + self.__modules[semester]= [] + + # the semester will be available as a key after this line, append module into semester + self.__modules[semester].append(module) + + def get_modules_by_semester(self, semester): + # returns Module list object from modules dictionary, using semester as key + return self.__modules[semester] + + @staticmethod + def fetchall(db): + # overrides the parent class fetchall abstract static method to + # create a list of Programme objects retrieved from database table programme. + # For each of the created Programme objects, + # The modules belongs to the particular programme + + output = [] + temp= {} + + with db.cursor() as cursor: + cursor.execute(f"USE {constants.DB_NAME};") + query = ''' +SELECT programme_id, mapping_semester, module_id, programme_name, module_name, module_credit +FROM programmes +INNER JOIN mappings ON programmes.programme_id = mappings.mapping_programme_id +INNER JOIN modules ON mappings.mapping_module_id = modules.module_id; + ''' + cursor.execute(query) + records = cursor.fetchall() + + # row => module, bloat modules + for row in records: + programme_id = row[0] + mapping_semester = row[1] + module_id = row[2] + programme_name = row[3] + module_name = row[4] + module_credit = row[5] + new_module = Module(module_id, module_name, module_credit) + + if not(programme_id in temp): + temp[programme_id] = {'_name': programme_name} + if not(mapping_semester in temp[programme_id] ): + temp[programme_id][mapping_semester] = [] + + temp[programme_id][mapping_semester].append(new_module) + + for programme_id in temp.keys(): + new_program = Programme(programme_id, temp[programme_id]['_name']) + # semester + for semester in temp[programme_id].keys(): + if (type(semester) == type(1)): + modules_in_semester = temp[programme_id][semester] + for module in modules_in_semester: + new_program.add_module(semester, module) + + output.append(new_program) + + return output + +class Module(MySQLObject): + def __init__(self, id, name, credit): + # initialize the id, name and credit attributes + self.__id = id # a non-public string to store the id of the module + self.__name = name # a non-public string to store the name of the module + self.__credit = credit # a non-public integer to store the credit of the module + + def __eq__(self, other): + # returns true of the id attribute is equal to the other object’s id attribute + if (hasattr(other,'get_id')): + return self.__id == other.get_id() + else: + return False + + def get_id(self): + # returns the id for this module + return self.__id + + def get_name(self): + # returns the name for this module + return self.__name + + def get_credit(self): + # returns the credit for this module + return self.__credit + + @staticmethod + def fetchall(db): + # fetchall overrides the parent class fetchall abstract static method to + # return a list of Module objects retrieved from database table module. + # Module objects will be created and appended into the + # returned list for every records retrieved from database. + query = "select module_id, module_name, module_credit from modules" + output = [] + + with db.cursor() as cursor: + cursor.execute(f"USE {constants.DB_NAME};") + cursor.execute(query) + records = cursor.fetchall() + for row in records: + module_id = row[0] + module_name = row[1] + module_credit = row[2] + output.append(Module(module_id, module_name, module_credit)) + + return output diff --git a/ITP4459_assignment_2023/src/python/readme.md b/ITP4459_assignment_2023/src/python/readme.md new file mode 100644 index 0000000..0e7458e --- /dev/null +++ b/ITP4459_assignment_2023/src/python/readme.md @@ -0,0 +1,11 @@ +```batch + +# start docker +docker compose up -d + +pipenv shell + +# inside shell +./run.bat + +``` diff --git a/ITP4459_assignment_2023/src/python/run.bat b/ITP4459_assignment_2023/src/python/run.bat new file mode 100644 index 0000000..c15aea0 --- /dev/null +++ b/ITP4459_assignment_2023/src/python/run.bat @@ -0,0 +1,10 @@ +@REM feed +@REM python ./main_db.py +python "./main_gui.py" + +@REM python ./test_combobox.py + +@REM python .\options_test.py +@REM python ".\models.py" + +@REM python ".\test_models.py" diff --git a/ITP4459_assignment_2023/src/python/widgets.py b/ITP4459_assignment_2023/src/python/widgets.py new file mode 100644 index 0000000..b94ac9c --- /dev/null +++ b/ITP4459_assignment_2023/src/python/widgets.py @@ -0,0 +1,92 @@ +import tkinter +from constants import GPA_MAPPING +import tkinter as tk +import tkinter.ttk as ttk +from pprint import pprint + +# widgets.py - Implements a custom GUI widget 'ModuleWidget' +# TODO: Remove all 'pass' statements and complete the implementation based on class description + +class ModuleWidget: + """A supplier class for displaying a module and returning the GPA value. + """ + def __init__(self, master, command): + self.__module = None + self.__command = command + self.__gpa = -1 + + self.setup_ui(master) + self.set_module(None) + + def set_module(self, module = None): + if (module != None): + # TODO: When module is provided: + # - Update UI to display module information + # - Enable option menu + + self.__var_name.set(module.get_name()) + self.__var_credit.set(module.get_credit()) + self.__ent_name['state'] = 'readonly' + self.__ent_credit['state'] = 'readonly' + self.__om_grade['state'] = 'readonly' + + else: + # - Clear entry content + # - Disable option menu + self.__var_name.set('') + self.__var_credit.set('') + self.__ent_name['state'] = 'disabled' + self.__ent_credit['state'] = 'disabled' + self.__om_grade['state'] = 'disabled' + + # Finally, update self.__module + self.__module = module + + def get_module(self): + return self.__module + + def get_frame(self): + return self.__frame + + def get_gpa(self): + return self.__gpa + + def setup_ui(self, master): + # Variables + + # Contianer + self.__frame = tkinter.Frame(master) + # pprint(self) + + # Module name + tkinter.Label(self.__frame, text = "Module", ).grid(row=0, column=0, padx=(0, 4), sticky=tkinter.W) + self.__var_name = tkinter.StringVar(value="") + self.__ent_name = ttk.Entry(self.__frame, textvariable=self.__var_name) + self.__ent_name.config(width=50) + self.__ent_name.grid(row=0, column=1, padx=(4, 4), sticky=tkinter.E+tkinter.W) + + # Module credit + tkinter.Label(self.__frame, text = "Credit", ).grid(row=0, column=2, padx=(0, 4), sticky=tkinter.W) + self.__var_credit = tkinter.StringVar(value="") + self.__ent_credit = ttk.Entry(self.__frame, textvariable=self.__var_credit) + self.__ent_credit['state'] = 'disabled' + self.__ent_credit.config(width=5) + self.__ent_credit.grid(row=0, column=3, padx=(4, 4), sticky=tkinter.E+tkinter.W) + + # Grade + tkinter.Label(self.__frame, text = "Grade", ).grid(row=0, column=4, padx=(0, 4), sticky=tkinter.W) + self.__var_grade = tk.StringVar() + self.__om_grade = ttk.Combobox(self.__frame, textvariable=self.__var_grade) + self.__om_grade.set('Please select') + self.__om_grade['values'] = [gpa for gpa in GPA_MAPPING.keys()] + self.__om_grade['state'] = 'disabled' + self.__om_grade.config(width=15) + self.__om_grade.grid(row=0, column=5, padx=(0, 4), sticky=tkinter.W) + self.__om_grade.bind('<>', self.on_grade_changed) + + def on_grade_changed(self, _): + # Get GPA based on combo box value + letter_grade = list(GPA_MAPPING.keys())[self.__om_grade.current()] + num_grade = GPA_MAPPING[letter_grade] + self.__gpa = num_grade + self.__command() diff --git a/ITP4459_assignment_2023/src/readme.md b/ITP4459_assignment_2023/src/readme.md new file mode 100644 index 0000000..0e88fc6 --- /dev/null +++ b/ITP4459_assignment_2023/src/readme.md @@ -0,0 +1,16 @@ +```bash +cd docker + docker compose build + docker compose up -d +cd .. + +# after docker up and running +cd python + pipenv shell + pipenv sync + +# inside pip environment +python main_db.py +python main_gui.py + +``` diff --git a/ITP4459_assignment_2023/src/scripts/dev.ps1 b/ITP4459_assignment_2023/src/scripts/dev.ps1 new file mode 100644 index 0000000..4619239 --- /dev/null +++ b/ITP4459_assignment_2023/src/scripts/dev.ps1 @@ -0,0 +1,19 @@ +pushd docker + + docker-compose pull + + docker-compose build + + docker-compose kill + docker-compose down + timeout 1 + + rmdir docker\volumes + + docker-compose up -d + + # docker-compose logs -f + + # docker-compose exec -it ubuntu bash + +popd diff --git a/ITP4459_assignment_2023/tests/case.md b/ITP4459_assignment_2023/tests/case.md new file mode 100644 index 0000000..2d013d3 --- /dev/null +++ b/ITP4459_assignment_2023/tests/case.md @@ -0,0 +1,106 @@ +# TEST CASE: + +- Name: Import data to MySQL database server + - Procedure + - Configure DB connection by editing `constants.py` + - Run `main_db.py` + - Start DBMS of your choice and validate the result. (phpmyadmin) + - Expected output + - Python file ran without errors and the database, + - tables and records are successfully created in database. + +- Name: GUI startup + - Procedure + - Run application via `main_gui.py` + - do nothing + + - Expected output + - show "Please select" at programme option menu + - show "Please select" at Semester option menu + - a empty list of module shown + +- Name: Select programme + - Procedure + - Run application via `main_gui.py` + - click programme option menu + - watch option available in option menu + + - Expected output + - show a list of programme available in DB + +- Name: after user select programme, user proceed to Select semester + - Procedure + - Run application via `main_gui.py` + - click programme option menu + - select "Higher Diploma in Cybersecurity" in option menu + - watch options available in "Semester" + + - Expected output + - 1,2,4,5 should be available in semester list + +- Name: user Selected semester, user proceed to input Grade + - Procedure + - run procedure "after user select programme, user proceed to Select semester" + - select semester "1" + + - Expected output + - the modules available to semester should be listed in the "Modules" frame + - the "Please Select" should be shown in every "Grade" option menu. + - a empty box should be displayed in the Module, Credit and Grade for every modules row for the rest + +- Name: user input grade, get total GPA + - Procedure + - run procedure "user Selected semester, user proceed to input Grade" + - input all gpa + + - Expected output + - watch the label at the bottom of the form. + - when not all gpa got answered, the gpa won't be updated (keep 0.00) + - when app gpa answered, the result gpa will be displayed (1.23) + +- Name: Screen update + - Procedure + - Run same procedure as stated in "GPA Calculation Test #2" + - re-select "Semester" to 2 + - re-select "Semester" to 4 + + - Expected output + - when "Semester" is 2 + - Module list should be updated (3 -> 2 items) + - Credit list should be updated (3 -> 2 items) + - Grade list should be selected "Please select" + - when "Semester" is 4 + - Module list should be updated (2 -> 1 items) + - Credit list should be updated (2 -> 1 items) + - Grade list should be selected "Please select" + +- Name: GPA Calculation Test #1 + - Procedure + - Run application via `main_gui.py` + - Perform semester GPA calculation with the input data stated in excepted output. + - Validate the result with expected output. + + - Input: + - Programme: Higher Diploma in Cybersecurity; Semester: 2 + - Subjects: + - "Vocational Chinese Communication: Putonghua Presentations, Administrative and Technical Text Writing" → A- + - "English & Communication: Reports" → C+ + + - Expected output + - Semester GPA: 3.00 shown at bottom + +- Name: GPA Calculation Test #2 + - Procedure + - Run application via `main_gui.py` + - Perform semester GPA calculation with the input data stated in excepted output. + - Validate the result with expected output. + + - Input: + - Programme: Higher Diploma in AI and Smart Technology; Semester: 1 + - Subjects: + - "Vocational Chinese Communication: Putonghua Conversation and Reports" → A + - "English & Communication: Workplace Interaction" → C- + - "English & Communication: Workplace Correspondance" → B+ + + - Expected output + - Semester GPA: 3.00 shown at bottom diff --git a/ITP4459_assignment_2023/tests/helloworld.py b/ITP4459_assignment_2023/tests/helloworld.py new file mode 100644 index 0000000..80417f6 --- /dev/null +++ b/ITP4459_assignment_2023/tests/helloworld.py @@ -0,0 +1 @@ +print('helloworld') diff --git a/ITP4459_assignment_2023/tests/options_test.py b/ITP4459_assignment_2023/tests/options_test.py new file mode 100644 index 0000000..5ff2355 --- /dev/null +++ b/ITP4459_assignment_2023/tests/options_test.py @@ -0,0 +1,35 @@ +import tkinter as tk +from tkinter import ttk + +root = tk.Tk() + +options = ['Option 1', 'Option 2', 'Option 3'] +variable = tk.StringVar(value=options[0]) + +def on_option_changed(*args): + print('helloworld') + # This function will be called whenever the selected option changes + # We will use it to update the option list based on the selected option + + # Get the selected option + selected_option = variable.get() + + # Update the option list based on the selected option + if selected_option == 'Option 1': + new_options = ['Option 1', 'Option 2', 'Option 3'] + elif selected_option == 'Option 2': + new_options = ['Option 4', 'Option 5', 'Option 6'] + else: + new_options = ['Option 7', 'Option 8', 'Option 9'] + + # Update the option list in the widget + combobox.configure(values=new_options) + +# Create the widget +combobox = ttk.Combobox(root, textvariable=variable, values=options) +combobox.pack() + +# Bind the on_option_changed function to the variable +variable.trace('w', on_option_changed) + +root.mainloop() diff --git a/ITP4459_assignment_2023/tests/test_combobox.py b/ITP4459_assignment_2023/tests/test_combobox.py new file mode 100644 index 0000000..600e354 --- /dev/null +++ b/ITP4459_assignment_2023/tests/test_combobox.py @@ -0,0 +1,41 @@ +import tkinter as tk +from tkinter import ttk +from tkinter.messagebox import showinfo +from calendar import month_name + +root = tk.Tk() + +# config the root window +root.geometry('300x200') +root.resizable(False, False) +root.title('Combobox Widget') + +# label +label = ttk.Label(text="Please select a month:") +label.pack(fill=tk.X, padx=5, pady=5) + +# create a combobox +selected_month = tk.StringVar() +month_cb = ttk.Combobox(root, textvariable=selected_month) + +# get first 3 letters of every month name +month_cb['values'] = [month_name[m][0:3] for m in range(1, 13)] + +# prevent typing a value +month_cb['state'] = 'readonly' + +# place the widget +month_cb.pack(fill=tk.X, padx=5, pady=5) + + +# bind the selected value changes +def month_changed(event): + """ handle the month changed event """ + showinfo( + title='Result', + message=f'You selected {selected_month.get()}!' + ) + +month_cb.bind('<>', month_changed) + +root.mainloop() diff --git a/ITP4459_assignment_2023/tests/test_models.py b/ITP4459_assignment_2023/tests/test_models.py new file mode 100644 index 0000000..eee6290 --- /dev/null +++ b/ITP4459_assignment_2023/tests/test_models.py @@ -0,0 +1,32 @@ +from pprint import pprint + +import constants + +from db import MySQLConnection +from models import Programme +from models import Module + +db = MySQLConnection( + host=constants.DB_HOST, + user=constants.DB_USER, + password=constants.DB_PASS +) + +list_program = Programme.fetchall(db) +list_module = Module.fetchall(db) + +# print(list_program[0].get_modules()) +# print(list_program[0].get_modules_by_semester(1)) +# print(list_program[0].get_name()) +# __eq__ +# print(list_program[0] == list_program[0]) + +# modules +# print(list_program[0].get_modules()[1][0][0].get_id()) +# pprint(list_program[0].get_modules()) +# pprint(list_program[0].get_modules_by_semester(1)[0]) +# print(list_program[0].get_modules()[1][0][0].get_credit()) + +db.close() + +# diff --git a/ITP4459_assignment_2023/tests/testcase.docx b/ITP4459_assignment_2023/tests/testcase.docx new file mode 100644 index 0000000..700dd89 Binary files /dev/null and b/ITP4459_assignment_2023/tests/testcase.docx differ diff --git a/gitUpdate.bat b/gitUpdate.bat new file mode 100644 index 0000000..310089c --- /dev/null +++ b/gitUpdate.bat @@ -0,0 +1,7 @@ +git status . + +@pause + +git add . +git commit -m"update daniel_jo," +start git push \ No newline at end of file diff --git a/meta.md b/meta.md new file mode 100644 index 0000000..982fa4f --- /dev/null +++ b/meta.md @@ -0,0 +1,5 @@ +--- +tags: [python, ITP4459] +--- + +# daniel_jo