adds login generator as OOP and MVC
This commit is contained in:
parent
b4b40f1790
commit
1b48d3f0e0
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue