diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c4a76e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,162 @@ +# 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/ + +database.db \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..a95162e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current Project", + "type": "python", + "request": "launch", + "program": "main.py", + "console": "integratedTerminal", + "justMyCode": true + } + ] +} \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..b576950 --- /dev/null +++ b/main.py @@ -0,0 +1,27 @@ +from models.utils import DatabaseUtils +from ui.selection_menu import SelectionMenu +from ui.input_menu import InputMenu +from services.encryption import Encryption +from models.database import Database + +def main(): + # main_menu = SelectionMenu("Main Menu").add_option("Login", damn).add_option("Exit", damn).display() + # action = main_menu.input_option() + # action() + + # main_form = InputMenu("User Information") + # main_form.add_option("USERNAME", "STR", "Username", 1, 254) + # main_form.add_option("PASSWORD", "STR", "Password", 1, 254) + # main_form.add_option("AGE", "INT", "Age", 5, 100) + + # main_form.do_input() + + # print(main_form.get_value("USERNAME")) + Database.init() + DatabaseUtils.init_city_data() + + +def damn(): + print("dsdd") + +main() \ No newline at end of file diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/city.py b/models/city.py new file mode 100644 index 0000000..88f4594 --- /dev/null +++ b/models/city.py @@ -0,0 +1,58 @@ +import sqlite3 + +class City: + def __init__(self, connection : sqlite3.Connection, id, name): + self.connection = connection + self.id = id + self.name = name + + def load_by_id(self): + cur = self.connection.cursor() + row = cur.execute("SELECT * FROM cities WHERE id = ?", (self.id,)).fetchone() + + if row == None: + return False + + self._set_row_values(row) + + cur.close() + return True + + def load_by_name(self): + cur = self.connection.cursor() + row = cur.execute("SELECT * FROM cities WHERE name = ?", (self.name,)).fetchone() + + if row == None: + return False + + self._set_row_values(row) + + cur.close() + return True + + def save(self): + cur = self.connection.cursor() + cur.execute(""" + INSERT INTO cities + (id, name) VALUES (?, ?) + """, (self.id, self.name)) + + self.connection.commit() + cur.close() + return True + + def update(self): + cur = self.connection.cursor() + cur.execute(""" + UPDATE cities SET + name = ?, + WHERE id = ? + """, (self.name, self.id)) + + self.connection.commit() + cur.close() + return True + + def _set_row_values(self, row): + self.id = row[0] + self.name = row[1] \ No newline at end of file diff --git a/models/database.py b/models/database.py new file mode 100644 index 0000000..888e739 --- /dev/null +++ b/models/database.py @@ -0,0 +1,63 @@ +from multiprocessing import connection +import sqlite3 + +from models.city import City + +class Database: + connection: sqlite3.Connection = None + + @staticmethod + def init(): + # Open connection with database + con = sqlite3.connect("./database.db") + Database.connection = con + + Database._init_log_table() + Database._init_user_table() + Database._init_city_table() + + @staticmethod + def _init_log_table(): + cursor = Database.connection.cursor() + q = cursor.execute(""" + CREATE TABLE IF NOT EXISTS logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT, + date TEXT, + time TEXT, + description TEXT, + additional_information TEXT, + suspicious BOOL + ) + """) + cursor.close() + + @staticmethod + def _init_user_table(): + cursor = Database.connection.cursor() + cursor.execute(""" + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY, + firstname TEXT, + lastname TEXT, + address TEXT, + zipcode TEXT, + city_id INTEGER, + email TEXT, + phone TEXT, + password TEXT, + role TEXT + ) + """) + cursor.close() + + @staticmethod + def _init_city_table(): + cursor = Database.connection.cursor() + cursor.execute(""" + CREATE TABLE IF NOT EXISTS cities ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT + ) + """) + cursor.close() \ No newline at end of file diff --git a/models/log.py b/models/log.py new file mode 100644 index 0000000..a040187 --- /dev/null +++ b/models/log.py @@ -0,0 +1,61 @@ +import sqlite3 + + +class Log: + def __init__(self, connection : sqlite3.Connection, id = None, username = None, date = None, time = None, description = None, additional_information = None, suspicious = None): + self.connection = connection + self.id = id + self.username = username + self.date = date + self.time = time + self.description = description + self.additional_information = additional_information + self.suspicious = suspicious + + def load_by_id(self): + cur = self.connection.cursor() + row = cur.execute("SELECT * FROM logs WHERE id = ?", (self.id,)).fetchone() + + if row == None: + return False + + self._set_row_values(row) + + cur.close() + return True + + def save(self): + cur = self.connection.cursor() + cur.execute(""" + INSERT INTO logs + (id, username, date, time, description, additional_information, suspicious) VALUES (?, ?, ?, ?, ?, ?, ?) + """, (self.id, self.username, self.date, self.time, self.description, self.additional_information, self.suspicious)) + + self.connection.commit() + cur.close() + return True + + def update(self): + cur = self.connection.cursor() + cur.execute(""" + UPDATE logs SET + username = ?, + date = ?, + description = ?, + additional_information = ?, + suspicious = ?, + WHERE id = ? + """, (self.firstname, self.lastname, self.zipcode, self.city_id, self.email, self.phone, self.password, self.role, self.id)) + + self.connection.commit() + cur.close() + return True + + def _set_row_values(self, row): + self.id = row[0] + self.username = row[1] + self.date = row[2] + self.time = row[3] + self.description = row[4] + self.additional_information = row[5] + self.suspicious = row[6] \ No newline at end of file diff --git a/models/user.py b/models/user.py new file mode 100644 index 0000000..48c8c40 --- /dev/null +++ b/models/user.py @@ -0,0 +1,72 @@ +import sqlite3 +from models.database import Database + +class User: + def __init__(self, connection : sqlite3.Connection, id = None, firstname = None, lastname = None, address = None, zipcode = None, city_id = None, email = None, phone = None, password = None, role = None): + self.connection = connection + self.id = id + self.firstname = firstname + self.lastname = lastname + self.address = address + self.zipcode = zipcode + self.city_id = city_id + self.email = email + self.phone = phone + self.password = password + self.role = role + + def load_by_id(self): + cur = Database.connection.cursor() + row = cur.execute("SELECT * FROM users WHERE id = ?", (self.id,)).fetchone() + + if row == None: + return False + + self._set_row_values(row) + + cur.close() + return True + + def save(self): + cur = Database.connection.cursor() + cur.execute(""" + INSERT INTO users + (id, fistname, lastname, address, zipcode, city_id, email, phone, password, role) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, (self.id, self.firstname, self.lastname, self.zipcode, self.city_id, self.email, self.phone, self.password, self.role)) + + Database.connection.commit() + cur.close() + return True + + def update(self): + cur = Database.connection.cursor() + cur.execute(""" + UPDATE users SET + fistname = ?, + lastname = ?, + address = ?, + zipcode = ?, + city_id = ?, + email = ?, + phone = ?, + password = ?, + role = ?, + WHERE id = ? + """, (self.firstname, self.lastname, self.zipcode, self.city_id, self.email, self.phone, self.password, self.role, self.id)) + + Database.connection.commit() + cur.close() + return True + + def _set_row_values(self, row): + self.id = row[0] + self.firstname = row[1] + self.lastname = row[2] + self.address = row[3] + self.zipcode = row[4] + self.city_id = row[5] + self.email = row[6] + self.phone = row[7] + self.password = row[8] + self.role = row[9] + \ No newline at end of file diff --git a/models/utils.py b/models/utils.py new file mode 100644 index 0000000..59a5e92 --- /dev/null +++ b/models/utils.py @@ -0,0 +1,46 @@ +from models.city import City +from models.database import Database + +class DatabaseUtils: + + @staticmethod + def init_city_data(): + new_city = City(Database.connection, None, "Haastrecht") + if not new_city.load_by_name(): + new_city.save() + + new_city = City(Database.connection, None, "Gouda") + if not new_city.load_by_name(): + new_city.save() + + new_city = City(Database.connection, None, "Rotterdam") + if not new_city.load_by_name(): + new_city.save() + + new_city = City(Database.connection, None, "Bruinisse") + if not new_city.load_by_name(): + new_city.save() + + new_city = City(Database.connection, None, "Amsterdam") + if not new_city.load_by_name(): + new_city.save() + + new_city = City(Database.connection, None, "Goes") + if not new_city.load_by_name(): + new_city.save() + + new_city = City(Database.connection, None, "Zoetermeer") + if not new_city.load_by_name(): + new_city.save() + + new_city = City(Database.connection, None, "Breda") + if not new_city.load_by_name(): + new_city.save() + + new_city = City(Database.connection, None, "Eindhoven") + if not new_city.load_by_name(): + new_city.save() + + new_city = City(Database.connection, None, "Almere") + if not new_city.load_by_name(): + new_city.save() \ No newline at end of file diff --git a/services/__init__.py b/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/services/checksum.py b/services/checksum.py new file mode 100644 index 0000000..42e7494 --- /dev/null +++ b/services/checksum.py @@ -0,0 +1,19 @@ +import random + +class IdChecksum: + @staticmethod + def generate(): + while True: + init_num = random.randint(1, 9) + id = [random.randint(0, 9) for _ in range(9)] + id.insert(0, init_num) + if IdChecksum.is_valid(id): + return "".join(str(x) for x in id) + + @staticmethod + def is_valid(checksum): + sum_digits = sum(checksum[:-1]) + if sum_digits % 10 == checksum[-1]: + return True + else: + return False \ No newline at end of file diff --git a/services/encryption.py b/services/encryption.py new file mode 100644 index 0000000..a0cd8f7 --- /dev/null +++ b/services/encryption.py @@ -0,0 +1,25 @@ +class Encryption: + @staticmethod + def vigenere(text: str, key: str, encrypt=True): + result = '' + + for i in range(len(text)): + letter_n = ord(text[i]) + key_n = ord(key[i % len(key)]) + + if encrypt: + value = (letter_n + key_n) % 1114112 + else: + value = (letter_n - key_n) % 1114112 + + result += chr(value) + + return result + + @staticmethod + def encrypt(text: str, key: str): + return Encryption.vigenere(text=text, key=key, encrypt=True) + + @staticmethod + def decrypt(text: str, key: str): + return Encryption.vigenere(text=text, key=key, encrypt=False) \ No newline at end of file diff --git a/ui/__init__.py b/ui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ui/input_menu.py b/ui/input_menu.py new file mode 100644 index 0000000..0d91503 --- /dev/null +++ b/ui/input_menu.py @@ -0,0 +1,49 @@ + +class InputMenu: + + def __init__(self, title): + self._title = title + self._fields = [] + + def add_option(self, key, type, title, min, max): + self._fields.append({"key": key, "title": title, "type": type, "value": None, "min": min, "max": max}) + return self + + def do_input(self): + print("") + print(f"/--[ {self._title} ]----------------------------") + + for i in range(len(self._fields)): + data = None + + while True: + data = input(f"| ({self._fields[i]['title']}) => ") + if self._fields[i]['type'] == "STR": + if len(data) > self._fields[i]['min'] and len(data) <= self._fields[i]['max']: + self._fields[i]['value'] = data + break + else: + print("| Invalid input! Try again. \n|") + + elif self._fields[i]['type'] == "INT": + try: + num = int(data) + if num > self._fields[i]['min'] and num <= self._fields[i]['max']: + self._fields[i]['value'] = data + break + else: + print("| Invalid input! Try again. \n|") + except: + print("| Invalid input! Try again. \n|") + else: + exit("Invalid input type!") + + print(f"\-------------------------------") + print("") + return self + + def get_value(self, key): + for i in range(len(self._fields)): + if self._fields[i]["key"] == key: + return self._fields[i]["value"] + return None diff --git a/ui/selection_menu.py b/ui/selection_menu.py new file mode 100644 index 0000000..d3e048f --- /dev/null +++ b/ui/selection_menu.py @@ -0,0 +1,34 @@ +class SelectionMenu: + + def __init__(self, title): + self.title = title + self.options = [] + + def add_option(self, title, callback): + self.options.append({"title": title, "callback": callback}) + return self + + def display(self): + print("") + print(f"/--[ {self.title} ]----------------------------") + for i in range(len(self.options)): + print(f"| {i}). {self.options[i]['title']}") + print(f"\-------------------------------") + print("") + return self + + def input_option(self): + try: + data = input("Selection: ") + index = int(data) + if index < 0 or index > len(self.options) - 1: + print("Please enter in a valid selection.") + return self.input_option() + return self.options[index]['callback'] + except: + print("Please enter in a valid selection.") + return self.input_option() + + + + \ No newline at end of file diff --git a/views/__init__.py b/views/__init__.py new file mode 100644 index 0000000..e69de29