diff --git a/learning_python3.md b/learning_python3.md index 65b8367..4255e6e 100644 --- a/learning_python3.md +++ b/learning_python3.md @@ -2760,7 +2760,339 @@ if __name__ == "__main__": ### Improve the login generator -TODO convert the login generator to a class +First the library... + +```python +Oimport string +import random +import json + + +def load_file(filepath): + words = [] + with open(filepath, "r") as fp: + data = fp.readlines() + for line in data: + word = line.strip() + words.append(word) + return words + + +class Login(object): + ADJECTIVES = load_file("adjectives.txt") + ANIMALS = load_file("subjects.txt") + + def __init__(self, site=None): + self.site = site + self.generate_password() + self.generate_username() + + def __str__(self): + msg = "site: {} - username: {} with password: {}".format(self.site, self.username, self.password) + return msg + + def generate_password(self, length=16, complex=False): + if complex: + db = list(string.ascii_letters + string.digits + string.punctuation) + else: + db = list(string.ascii_letters) + password = [] + for i in range(0, length): + char = random.choice(db) + password.append(char) + password = "".join(password) + self.password = password + + def generate_username(self): + """generates a random username from a list of animals and adjectives""" + adj = random.choice(self.__class__.ADJECTIVES) + sbj = random.choice(self.__class__.ANIMALS) + username = f"{adj.capitalize()}{sbj.capitalize()}" + self.username = username + + def set_password(self, password): + self.password = password + + def set_username(self, username): + self.username = username + + def verify_password(self, password): + if password == self.password: + return True + return False + + def verify_username(self, username): + if username == self.username: + return True + return False + + def verify_login(self, username, password): + # if password == self.password and username == self.username: + if self.verify_password(password) and self.verify_username(username): + return True + return False + + +class Database(object): + def __init__(self, path="db.json"): + self.path = path + self.data = [] + + def add(self, login): + if isinstance(login, Login): + self.data.append(login) + + def get_all(self): + return self.data + + def get_by_index(self, index): + if index in range(0, len(self.data)): + return self.data[index] + + def save_to_disk(self): + with open(self.path, "w") as fp: + json.dump(self.data, fp , default=vars) + + def load_from_disk(self): + with open(self.path, "r") as fp: + data = json.load(fp) + for item in data: + l = Login(item["site"]) + l.set_password(item["password"]) + l.set_username(item["username"]) + self.data.append(l) + + +if __name__ == "__main__": + db = Database() + db.load_from_disk() + for login in db.data: + print(login) + login.generate_password() + db.save_to_disk() +``` + +Now the command line interface with a **bad** separation of responsibilities. + +```python +from login_lib_OOP import Login, Database + + +class CommandLineInterface(object): + def __init__(self, db): + self.db = db + + def ask_for_int(self, msg): + while True: + result = input(msg) + if result.isdigit(): + number = int(result) + break + print("only intergers please...") + return number + + def ask_for_bool(self, msg): + while True: + result = input(msg).lower() + if result.startswith("y"): + status = True + break + elif result.startswith("n"): + status = False + break + print("answer with y(es)/n(o) please...") + return status + + def ask_for_view(self): + msg = "do you want to view your logins?" + status = self.ask_for_bool(msg) + + def ask_for_add_logins(self): + msg = "how many logins do you want to add?" + number = self.ask_for_int(msg) + for i in range(0, number): + l = Login("undefined") + self.db.add(l) + + def view_logins(self): + for login in self.db.data: + print("\t{}: {}".format(self.db.data.index(login), login)) + + def main_menu(self): + actions = ["show logins", "add logins", "save to disk","load from disk", "quit"] + for action in actions: + print("{}: {}".format(actions.index(action), action)) + msg = "what do you want to do?" + action = self.ask_for_int(msg) + if action == 0: + self.view_logins() + elif action == 1: + self.ask_for_add_logins() + elif action == 2: + self.db.save_to_disk() + elif action == 3: + self.db.load_from_disk() + elif action == 4: + return False + return True + + def run(self): + while True: + status = self.main_menu() + if not status: + break + + +if __name__ == "__main__": + db = Database() + app = CommandLineInterface(db) + app.run() +``` + +Now a minimal **MVC** version... + +```python +from login_lib_OOP import Login, Database + + +class Controller(object): + def __init__(self, model): + self.model = model + + def set_view(self, view): + self.view = view + + def add_multiple_logins(self, number): + for i in range(0, number): + l = Login() + self.model.add(l) + self.view.show_message("added {}".format(l)) + + def get_all_logins(self): + data = self.model.get_all() + self.view.show_message("there are {} logins in your database".format(len(data))) + for login in data: + msg = "{}: {}".format(data.index(login), login) + self.view.show_data(msg) + + def get_one_login(self, index): + login = self.model.get_all()[index] + return login + + def load(self): + self.model.load_from_disk() + number = len(self.model.get_all()) + self.view.show_message("loaded {} logins from disk".format(number)) + + def save(self): + self.model.save_to_disk() + number = len(self.model.get_all()) + self.view.show_message("saved {} logins to disk".format(number)) + + +class CommandLineInterface(object): + def __init__(self, controller): + self.controller = controller + + def ask_for_int(self, msg): + while True: + result = input(msg) + if result.isdigit(): + number = int(result) + break + print("only intergers please...") + return number + + def ask_for_bool(self, msg): + while True: + result = input(msg).lower() + if result.startswith("y"): + status = True + break + elif result.startswith("n"): + status = False + break + print("answer with y(es)/n(o) please...") + return status + + def ask_for_login_index(self): + msg = "which login do you want to modify?" + number = self.ask_for_int(msg) + return number + + def show_data(self, msg): + print("\t{}".format(msg)) + + def show_message(self, msg): + print("MSG: {}".format(msg)) + + def show_header(self, msg): + print(msg) + print(len(msg) * "-") + + def main_menu(self): + self.show_header("main menu:") + actions = ["show logins", "add logins", "save to disk", "load from disk", "modify a login", "quit"] + for action in actions: + print("{}: {}".format(actions.index(action), action)) + msg = "what do you want to do?" + action = self.ask_for_int(msg) + if action == 0: + self.controller.get_all_logins() + elif action == 1: + msg = "how many logins do you want?" + number = self.ask_for_int(msg) + self.controller.add_multiple_logins(number) + elif action == 2: + self.controller.save() + elif action == 3: + self.controller.load() + elif action == 4: + self.sub_menu_modify() + elif action == 5: + return False + return True + + def sub_menu_modify(self): + self.show_header("modify entry:") + msg = "which login do you want to modify?" + number = self.ask_for_int(msg) + login = self.controller.get_one_login(number) + msg = "do you want to change the site name?" + status = self.ask_for_bool(msg) + if status: + login.site = input("for which site is this login?") + self.show_message("set site to: {}".format(login.site)) + msg = "do you want to renew the username?" + status = self.ask_for_bool(msg) + if status: + login.generate_username() + self.show_message("set username to: {}".format(login.username)) + msg = "do you want to renew the password?" + status = self.ask_for_bool(msg) + if status: + login.generate_password() + self.show_message("set password to: {}".format(login.password)) + msg = "save changes?" + status = self.ask_for_bool(msg) + if status: + self.controller.save() + + def run(self): + while True: + status = self.main_menu() + if not status: + break + + +if __name__ == "__main__": + model = Database() + controller = Controller(model) + view = CommandLineInterface(controller) + controller.set_view(view) + view.run() + +``` ### Improve the task manager