This commit is contained in:
louiscklaw
2025-01-31 19:38:17 +08:00
parent b7e6ca17ef
commit 5ea2c37f8d
124 changed files with 3736 additions and 0 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,7 @@
# MENTIONS:
### word test_plan.docx
![](./f3wV3PnOix.png)
### need to brief ?
![](./need_to_brief.png)

Binary file not shown.

Binary file not shown.

View File

@@ -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

View File

@@ -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

View File

@@ -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','<br />'))
.replace(' 4 ',x['expected_output'].replace('\n','<br />'))
.replace(' 5 ',f'''
![](./screenshots/test{str(cases.index(x)+1)}.png)
'''.replace('\n','<br />'))
.replace(' 6 ',x['result'])
,cases))))
# D:\\\\_workspace\\daniel_jo_assignment_student\\screenshots\\test{str(cases.index(x)+1)}.png

View File

@@ -0,0 +1,5 @@
def print_helloworld():
print('print_helloworld')

View File

@@ -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

View File

@@ -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.<br />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

View File

@@ -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 employees 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()

View File

@@ -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

View File

@@ -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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,31 @@
| ID | Test Case Name | Procedure | Expected Output | Screen Dump | Result |
| --- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------- | -------------- |
| 1 | Display all employees in the system | 1. Start program.<br />2. input 1 for display all employee | All employees' information including their employee ID, name, salary and department should be displayed | <br /> ![](./screenshots/test1.png) <br /> | 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<br />2. Input 'Pika Chiu' for employee's name Input "15000" for salary<br />3. Input "IT" for IT department | A success message "Employee Added Successfully" should be displayed | <br /> ![](./screenshots/test2.png) <br /> | Pass/ ~~Fail~~ |
| 3 | Remove an employee with valid employee id | 1. In the employee management system menu, input '3' to Remove an employee<br />2. Input 'IVE00006' for employee's id | A success message "Employee Removed Successfully" should be displayed | <br /> ![](./screenshots/test3.png) <br /> | Pass/ ~~Fail~~ |
| 4 | Update an employee with valid employee id | 1. In the employee management system menu, input '4' to Update an employee<br />2. Input 'IVE00005' for employee's id<br />3. Input '99999' for employee's salary | A success message "Employee Updated Successfully" should be displayed | <br /> ![](./screenshots/test4.png) <br /> | Pass/ ~~Fail~~ |
| 5 | Display company statistics | 1. In the employee management system menu, input '5' to Update an employee | <br />1. a list of all employee information listed<br />2. total number of staff listed<br />3. staff with highest salary listed<br />4. staff with lowest salary listed<br />5. average salary listed<br /> | <br /> ![](./screenshots/test5.png) <br /> | Pass/ ~~Fail~~ |
| 6 | exiting system | 1. In the employee management system menu, input "ENTER"(enter key) to exit system | <br />1. system exit <br /> | <br /> ![](./screenshots/test6.png) <br /> | Pass/ ~~Fail~~ |
| 7 | main menu invalid input handling | 1. In the employee management system menu, input "~" to main menu | <br />1. screen showing "input digit contains non-int value, accepted values are 1,2,3,4,5" alert to user<br /> | <br /> ![](./screenshots/test7.png) <br /> | Pass/ ~~Fail~~ |
| 8 | main menu invalid input handling | 1. In the employee management system menu, input "a" to main menu | <br />1. screen showing "input digit contains non-int value, accepted values are 1,2,3,4,5" alert to user<br /> | <br /> ![](./screenshots/test8.png) <br /> | Pass/ ~~Fail~~ |
| 9 | Add an employee (invalid employee name) | 1. In the employee management system menu, input '2' to add an employee<br />2. Input 'a1' for employee's name (this is invalid name)<br />3. Input '123' for employee's name (this is invalid name)<br />4. Input '4a' for employee's name (this is valid name)<br />5. Input 'apple' for employee's name (this is valid name)<br />6. Input "99999" for salary<br />7. Input "IT" for IT department | <br />1. showing "ERROR: sorry but the employee name should not contain digit" alert to user<br />2. keep asking "Please input employee's name, Enter to return:" until valid name get<br />3. after getting apple as name, get back to normal employee adding flow<br /> | <br /> ![](./screenshots/test9.png) <br /> | Pass/ ~~Fail~~ |
| 10 | Add an employee (invalid employee salary) | 1. In the employee management system menu, input '2' to add an employee<br />2. Input 'apple' for employee's name (this is valid name)<br />3. Input "aaaaa" for salary (invalid input as contains text)<br />4. Input "11111" for salary (valid input)<br />5. Input "IT" for IT department | <br />1. showing "ERROR: Employee's salary contains non digit value" alert to user<br />2. keep asking "Please input employee's salary, Enter to return:" until valid salary get<br />3. after getting valid salary, get back to normal employee adding flow<br /> | <br /> ![](./screenshots/test10.png) <br /> | Pass/ ~~Fail~~ |
| 11 | Add an employee (invalid employee department) | 1. In the employee management system menu, input '2' to add an employee<br />2. Input 'apple' for employee's name (this is valid name)<br />3. Input "11111" for salary (valid input)<br />4. Input "Marketing" (invalid input)<br />5. Input "IT" (valid input) | <br />1. showing "ERROR: Not a valid department, the valid options are HR, IT, Admin, Finance" alert to user<br />2. keep asking "Please input employee's department, Enter to return:" until valid department get<br />3. after getting valid department, show "**\*** Employee Added Successfully"<br /> | <br /> ![](./screenshots/test11.png) <br /> | Pass/ ~~Fail~~ |
| 12 | Remove an employee (invalid employee id, not existing) | 1. In the employee management system menu, input '3' to remove an employee<br />2. Input 'IVE00007' for employee's id (this is invalid id, not exist)<br />2. Input "IVE00006" for employee's id (valid input, existing id) | <br />1. showing "ERROR: sorry but the input id not found" alert to user<br />2. keep asking "Please input employee's id, Enter to return:" until valid id get<br />3. after getting valid id, show "**\*** Employee Removed Successfully"<br /> | <br /> ![](./screenshots/test12.png) <br /> | Pass/ ~~Fail~~ |
| 13 | Remove an employee (invalid employee id, invalid format) | 1. In the employee management system menu, input '3' to remove an employee<br />2. Input 'III00007' for employee's id (this is invalid id, not exist)<br />2. Input "IVE00006" for employee's id (valid input, existing id) | <br />1. showing "ERROR: sorry but the input id not found" alert to user<br />2. keep asking "Please input employee's id, Enter to return:" until valid id get<br />3. after getting valid id, show "**\*** Employee Removed Successfully"<br /> | <br /> ![](./screenshots/test13.png) <br /> | Pass/ ~~Fail~~ |
| 14 | Remove an employee (invalid employee id, invalid format) | 1. In the employee management system menu, input '3' to remove an employee<br />2. Input 'a' for employee's id (this is invalid id)<br />2. Input "IVE00006" for employee's id (valid input, existing id) | <br />1. showing "ERROR: sorry but the input id not found" alert to user<br />2. keep asking "Please input employee's id, Enter to return:" until valid id get<br />3. after getting valid id, show "**\*** Employee Removed Successfully"<br /> | <br /> ![](./screenshots/test14.png) <br /> | Pass/ ~~Fail~~ |
| 15 | Remove an employee (invalid employee id, invalid format) | 1. In the employee management system menu, input '3' to remove an employee<br />2. Input '11111111' for employee's id (this is invalid id)<br />3. Input "IVE00006" for employee's id (valid input, existing id) | <br />1. showing "ERROR: sorry but the input id not found" alert to user<br />2. keep asking "Please input employee's id, Enter to return:" until valid id get<br />3. after getting valid id, show "**\*** Employee Removed Successfully"<br /> | <br /> ![](./screenshots/test15.png) <br /> | Pass/ ~~Fail~~ |
| 16 | Update an employee (invalid employee id, invalid format) | 1. In the employee management system menu, input '4' to update an employee<br />2. Input '1' for employee's id (this is invalid id)<br />3. Input "IVE00006" for employee's id (valid input, existing id)<br />4. Input "11111" for employee's id (valid input) | <br />1. showing "ERROR: sorry but the input id not found" alert to user<br />2. keep asking "Please input employee's id, Enter to return:" until valid id get<br />3. after getting valid id, get back to normal update employee flow<br /> | <br /> ![](./screenshots/test16.png) <br /> | Pass/ ~~Fail~~ |
| 17 | Update an employee (invalid salary) | 1. In the employee management system menu, input '4' to update an employee<br />2. Input "IVE00006" for employee's id (valid employee id, existing id)<br />3. Input "a" for salary (invalid input, salary cannot be non integer value)<br />4. Input "$" for salary (invalid input, salary cannot be non integer value)<br />5. Input "111" for salary (value input, integer value only) | <br />1. showing "ERROR: Employee's salary contains non digit value" alert to user<br />2. keep asking "Please input employee's salary, Enter to return:" until valid salary get<br />3. after getting valid salary, show "**\*** Employee Updated Successfully" to user<br /> | <br /> ![](./screenshots/test17.png) <br /> | Pass/ ~~Fail~~ |
| 18 | display highest salary | 1. In the employee management system menu, input '5' get current snap of employee table<br />2. In the employee management system menu, input '2' to add an employee<br />3. Input "highest_employee" for name (valid employee name)<br />4. Input "9999999" for salary (valid highest salary)<br />5. Input "IT" for department (valid department)<br />6. Input "5" to check the highest salary got updated | <br />1. showing "highest_employee" in staff name field with highest salary<br /> | <br /> ![](./screenshots/test18.png) <br /> | Pass/ ~~Fail~~ |
| 19 | display lowest salary | 1. In the employee management system menu, input '5' get current snap of employee table<br />2. In the employee management system menu, input '2' to add an employee<br />3. Input "lowest_employee" for name (valid employee name)<br />4. Input "10" for salary (valid lowest salary)<br />5. Input "IT" for department (valid department)<br />6. Input "5" to check the lowest salary got updated | <br />1. showing "lowest_employee" in staff name field with lowest salary<br /> | <br /> ![](./screenshots/test19.png) <br /> | Pass/ ~~Fail~~ |
| 20 | update statistics after adding user | 1. In the employee management system menu, input '5' get current snap of employee table<br />2. In the employee management system menu, input '2' to add an employee<br />3. Input "new_user" for name (valid employee name)<br />4. Input "10" for salary (valid high salary)<br />5. Input "IT" for department (valid department)<br />6. Input "5" to check the lowest salary got updated | <br />1. number of staff = "6" + "1" = "7"<br /> | <br /> ![](./screenshots/test20.png) <br /> | Pass/ ~~Fail~~ |
| 21 | update statistics after remove user | 1. In the employee management system menu, input '5' get current snap of employee table<br />2. In the employee management system menu, input '3' to remove an employee<br />3. Input "IVE00006" for id (valid employee id) | <br />1. number of staff = "6" - "1" = "5"<br /> | <br /> ![](./screenshots/test21.png) <br /> | Pass/ ~~Fail~~ |
| 22 | update average after adding user | 1. In the employee management system menu, input '5' get current snap of employee table<br />2. In the employee management system menu, input '2' to add an employee<br />3. Input "new_user" for name (valid employee name)<br />4. Input "10" for salary (valid high salary)<br />5. Input "IT" for department (valid department)<br />6. Input "5" to check the average salary got updated | <br />1. average salary changed from $19814.78 to $16,985.53 (average of "7" employee)<br /> | <br /> ![](./screenshots/test22.png) <br /> | Pass/ ~~Fail~~ |
| 23 | update average after remove user | 1. In the employee management system menu, input '5' get current snap of employee table<br />2. In the employee management system menu, input '3' to add an employee<br />3. Input "IVE00001" for id (valid employee id)<br />4. Input "5" to check the average salary got updated | <br />1. average salary changed from $19814.78 to $15135.64 (average of "5" employee)<br /> | <br /> ![](./screenshots/test23.png) <br /> | Pass/ ~~Fail~~ |
| 24 | add employee (cancelling) | 1. In the employee management system menu, input '2' to add an employee<br />2. Input "ENTER"(one key) for name (cancelling the add flow) | <br />1. showing "**\*** Employee Add cancelled"<br />2. back to the main menu<br /> | <br /> ![](./screenshots/test24.png) <br /> | Pass/ ~~Fail~~ |
| 25 | add employee (cancelling) | 1. In the employee management system menu, input '2' to add an employee<br />2. Input "apple" for name (valid name)<br />3. Input "ENTER"(one key) for name (cancelling the add flow) | <br />1. showing "Please input employee's name, Enter to return:"<br />2. after receiving valid name, showing "Please input employee's salary, Enter to return:"<br />3. after pressing "ENTER"(one key), showing "**\*** Employee Add cancelled"<br />4. back to the main menu<br /> | <br /> ![](./screenshots/test25.png) <br /> | Pass/ ~~Fail~~ |
| 26 | add employee (cancelling) | 1. In the employee management system menu, input '2' to add an employee<br />2. Input "apple" for name (valid name)<br />3. Input "100" for salary (valid salary)<br />4. Input "ENTER"(one key) for department (cancelling the add flow) | <br />1. showing "Please input employee's name, Enter to return:"<br />2. after receiving valid name, showing "Please input employee's salary, Enter to return:"<br />3. after receiving valid salary, showing "Please input employee's department, Enter to return:"<br />4. after pressing "ENTER"(one key), showing "**\*** Employee Add cancelled"<br />5. back to the main menu<br /> | <br /> ![](./screenshots/test26.png) <br /> | Pass/ ~~Fail~~ |
| 27 | remove employee (cancelling) | 1. In the employee management system menu, input '3' to remove an employee<br />2. Input "ENTER"(one key) for id (cancelling the remove flow) | <br />1. showing "**\*** Employee remove cancelled"<br /> | <br /> ![](./screenshots/test27.png) <br /> | Pass/ ~~Fail~~ |
| 28 | update employee (cancelling) | 1. In the employee management system menu, input '4' to update an employee<br />2. Input "ENTER"(one key) for id (cancelling the update flow) | <br />1. showing "**\*** Employee update cancelled"<br /> | <br /> ![](./screenshots/test28.png) <br /> | Pass/ ~~Fail~~ |
| 29 | update employee (cancelling) | 1. In the employee management system menu, input '4' to update an employee<br />2. Input "IVE00006" for name (valid name)<br />3. Input "ENTER"(one key) for salary (cancelling the update flow) | <br />1. showing "Please input employee's id, Enter to return:"<br />1. showing "Please input employee's salary, Enter to return:"<br />1. after pressing "ENTER"(one key),<br />1. showing "**\*** Employee update cancelled"<br /> | <br /> ![](./screenshots/test29.png) <br /> | Pass/ ~~Fail~~ |

View File

@@ -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

View File

@@ -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

Binary file not shown.

View File

@@ -0,0 +1,5 @@
---
tags: [python, ITP4459]
---
# daniel_jo

View File

@@ -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"

View File

@@ -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": {}
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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=="
}
}
}

Some files were not shown because too many files have changed in this diff Show More