Last active
October 31, 2019 21:21
-
-
Save quirksubdol/8390e53e70db2c03cb05ecf22408ca1e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ---------------------------------------------------------------------------------------------------------------------- # | |
# The current version of the program is functioning in a certain cycle that i wont try to work around, but i will explain# | |
# as best as i can. The pickle file that holds the accounts, in a username/password format gets overwritten every time # | |
# the the user signs up accounts. # | |
# So, the first time your run the program and select to sign up, the user accounts you create, will remain in the pickle # | |
# file after you close the program. If the next time you run the program you select to login instead, the # | |
# pickled file will have the accounts you created previously. If by mistake you select to sign up, you can always close # | |
# the sign up window, and the pickled file wont be affected. Basically, every time you hit the submit button in the # | |
# sign up window and it's successful, the file is being overwritten. # | |
# # | |
# There was also a mechanic of the PySimpleGUI itself that prevented me from creating a smoother program in terms of flow# | |
# and that was the layouts. When a layout is loaded through the window function, that layout cannot be used again by the # | |
# method. For example, the user cant go back to the login page after he has pressed the Sign up button # | |
# So instead, i just worked with a limited number of layouts and used the pickler so the data could at least be # | |
# available in some way after the program was closed. # | |
# ---------------------------------------------------------------------------------------------------------------------- # | |
# Moving to the LOGIN page functionality after the Welcome window. # | |
# You can fill your username and password wrongly as many times as you like, the window remains active and ready to # | |
# receive input until you have successfully logged in. The page that will be displayed afterwards, depending on the type # | |
# of account is just to show each account's permissions, except for the ADMIN page which i have added a little # | |
# functionality. # | |
# -----------------------------------------------------------------------------------------------------------------------# | |
# PySimpleGUI is a feature of python that lets the user use a GUI | |
# from typing import BinaryIO | |
import PySimpleGUI as sg | |
# we will need to save usernames and passwords in a file for the accounts | |
# thus the pickle import | |
import pickle | |
# The list we will use to save the users in the pickled file | |
Accounts = [] | |
# Special Char arrays for testing password strength | |
# Also for testing if a valid password string is entered | |
special = ['!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', | |
']', '^', '_', '`', '{', '|', '}', '~'] | |
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', | |
'v', 'w', 'x', 'y', 'z'] | |
caps = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', | |
'W','X', 'Y', 'Z'] | |
numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] | |
# ------------------------------------------------------------------------------------- | |
# The layouts of the windows to be used, there is one for signing up and one for log in | |
# The Welcome_layout simply prompts the user to do either of those things with buttons | |
# Additional layout were added for the Login part of the assessment. | |
# The windows for the 3 types of accounts just show a window where the permissions of | |
# each account type are represented with buttons. | |
# ------------------------------------------------------------------------------------- | |
Sign_layout = [[sg.Text('Please complete the fields below')], | |
[sg.Text('First Name'), sg.InputText(size=[20, 1])], | |
[sg.Text('Last Name'), sg.InputText(size=[20, 1])], | |
[sg.Text('Password'), sg.InputText(size=[20, 1]), | |
sg.Text('Strength:'), | |
sg.ProgressBar(max_value=100, orientation='horizontal', size=(15, 12), key='progressbar')], | |
[sg.Text('Password'), sg.InputText(size=[20, 1]), sg.Button('Check Password')], | |
[sg.Checkbox('Admin Account', default=False), sg.Checkbox('Management Staff', default=False), | |
sg.Checkbox('Public Account', default=False)], | |
[sg.Button('Submit'), sg.Button('Cancel')], | |
[sg.T('Continue to '), sg.B('LOGIN')]] | |
Login_layout = [[sg.Text('Username'), sg.InputText()], | |
[sg.Text('Password'), sg.InputText()], | |
[sg.Button('Ok'), sg.Button('Cancel')]] | |
Welcome_layout = [[sg.Text('New user?')], | |
[sg.Button('Sign up')], | |
[sg.Text('OR')], | |
[sg.Button('LOGIN')]] | |
# ------------------------------------------------------------------------- | |
# Additional layouts for the 3 different kinds of accounts created | |
# Admin, Management and Public with the account permissions shown as Button | |
# ------------------------------------------------------------------------- | |
Admin_layout = [[sg.Text('Logged in as ADMINISTRATOR')], | |
[sg.Button('Print all users')], | |
[sg.Button('Delete User')], | |
[sg.Button('Change User Permissions')]] | |
Mod_layout = [[sg.Text('Logged in as MANAGER')], | |
[sg.Button('Edit Stock')], | |
[sg.Button('Order Supplies')], | |
[sg.Button('Manage Clients')], | |
[sg.Button('Manage Shipments')]] | |
Public_layout = [[sg.Text('Welcome, Guest')], | |
[sg.Button('View Stock')]] | |
# ------------------------- | |
# Create the Welcome Window | |
# ------------------------- | |
window = sg.Window('Welcome!', Welcome_layout) | |
# -------------------------------------------------------------- | |
# Event loop for the the windows | |
# The while loop ensures that when in a window, the window wont | |
# close unless a certain button is pushed by the user | |
# Also reads all the values of the window fields and key presses | |
# -------------------------------------------------------------- | |
while True: | |
submit: str = "" # variable for checking valid user creation | |
event, values = window.read() # Read the events on the window(clicks) | |
if event in (sg.Button, 'Sign up'): # Button 'Sign up' is pressed | |
window.close() # Window closes | |
window = sg.Window('Sign Up!', Sign_layout) # Sign up window opens up | |
progress_bar = window.FindElement( | |
'progressbar') # This binds the progress bar form the window to a variable | |
# we can access and edit | |
while True: | |
event, values = window.read() # Read the events in that window | |
if event in (None, 'Cancel'): # If the user presses the Cancel button | |
window.close() # Window closes and the program exits | |
break | |
# Wanted to implement a dynamic kind of flow to the program, | |
# but it turns out i have to write duplicate code for that | |
# so i will keep it simpler | |
# Login here just takes the user to the LOGIN window, | |
# but with no functionality | |
if event in (sg.Button, 'LOGIN'): | |
window.close() | |
window = sg.Window('LOGIN', Login_layout) | |
if event == 'Check Password': # This is for testing password strength | |
# print(values[2][0]) # The loops compare each char of the password with | |
# print(values[2].__len__()) # the 4 arrays letters, caps, numbers, special | |
count_let: int = 0 # Initializing the counters for the array comparison | |
count_caps: int = 0 # // | |
count_nums: int = 0 # // | |
count_sp: int = 0 # // | |
for i in range(0, | |
values[2].__len__()): # and increase the counter's value by 1 each time | |
# there is a match | |
for j in range(0, letters.__len__()): # check letters array | |
if values[2][i] == letters[j]: # match found in the [i] position of the password | |
# array (values[2]) | |
count_let += 1 # counter increases by 1, loop exits from letters | |
# array and | |
for k in range(0, caps.__len__()): # first loop checks the next char of the password | |
if values[2][i] == caps[k]: # Same process with all 4 arrays | |
count_caps += 1 | |
for l in range(0, numbers.__len__()): | |
if values[2][i] == numbers[l]: | |
count_nums += 1 | |
for m in range(0, special.__len__()): | |
if values[2][i] == special[m]: | |
count_sp += 1 | |
# ------------------------------------------------------------------------------------- # | |
# When the parsing of the string is finished, the total password strength is calculated # | |
# Each counter's value is multiplied by the array's value (3, 6, 8 ,10) # | |
# This calculation happens after the password string has been compared # | |
# to all the characters from each special array # | |
# ------------------------------------------------------------------------------------- # | |
progress_bar.UpdateBar(3 * count_let + 6 * count_caps + 8 * count_nums + 10 * count_sp) | |
if event in (sg.Button, 'Submit'): # If user presses Submit | |
print('', values) # Print the different values of the user input | |
if values[0] == '': # Checks for empty fields and passwords mismatch | |
sg.Popup('Provide first name') | |
elif values[1] == '': | |
sg.Popup('Provide last name') | |
elif values[2] == '': | |
sg.Popup('Provide a password') | |
elif values[3] != values[2]: | |
sg.Popup("Passwords don't match") | |
elif not (values[4] | values[5] | values[6]): | |
sg.Popup('Please choose the type of account you wish to create') | |
elif (values[4] & values[5]) | (values[4] & values[6]) | (values[5] & values[6]) | ( | |
values[4] & values[5] & values[6]): | |
sg.Popup('Please only choose one type') | |
else: | |
submit = "ok" | |
if submit == "ok": | |
username: str = '' | |
if values[4]: # If the user creates an Admin account | |
username = 'su_' + values[0] # in order to create the username we get the string from | |
# values[0] which is the first name | |
Accounts.insert(0, [username, values[2]]) # and append the string "su_" in the front. | |
# Then the username and password are saved in the | |
# Accounts array | |
if values[5]: # When the user creates a management account | |
username = 'mod_' + values[0] # the prefix 'mod_' is added in front of the first name | |
Accounts.insert(0, [username, values[2]]) | |
if values[6]: # When a public account is created | |
username = 'p_' + values[0] # a 'p_' prefix is added to the first name | |
Accounts.insert(0, [username, values[2]]) | |
print(Accounts[0][0]) # Only for debugging purposes | |
new_user = open("AccountsFile.pck", "wb") # The file "AccountsFile" is opened with the | |
# overwrite property | |
pickle.dump(Accounts, new_user) # The Accounts array is saved in the file | |
new_user.close() # File closes | |
read_users = open("AccountsFile.pck", "rb") # Lines for debugging purposes, open the file to read | |
print_users = pickle.load(read_users) # checking if saving, appending, file writing | |
print(print_users) # are working as expected | |
sg.Popup('Account Created!') # Successful submission popup window | |
sg.Popup('Your Username: ', username, 'Your Password: ', values[2]) | |
submit = '' # submit variable resets so the next account won't be | |
# submitted | |
# after pressing the 'Check Password' button | |
# ---------------------------------- | |
# LOGIN Selection in Welcome Window | |
# ---------------------------------- | |
elif event in (sg.Button, 'LOGIN'): | |
window.close() | |
window = sg.Window('LOGIN', Login_layout) | |
while True: | |
event, values = window.read() | |
if event in (None, 'Cancel'): # If the user presses the Cancel button | |
window.close() # Window closes and the program exits | |
break | |
if event in (sg.Button, 'Ok'): # When the Ok button is pressed | |
if values[0] == '': # if the username is empty | |
sg.Popup('Provide a username!') | |
elif values[1] == '': # if the password is empty | |
sg.Popup('Provide a password') | |
else: # if the user fills the fields | |
users = open("AccountsFile.pck", 'rb') # the program checks the pickled file | |
accs = pickle.load(users) # loads the data into a list | |
users.close() | |
print(accs) # debugging print | |
match: bool = False | |
u_match: bool = False | |
for i in range(len(accs)): # loop that checks every list element for matches | |
print(accs[i]) # console debugging prints | |
# print(len(accs)) # \\ | |
if (values[0] == accs[i][0]) & (values[1] == accs[i][1]): # if username and password match | |
match = True | |
print('match') # debug | |
if accs[i][0][0] == 's': # user is an admin account | |
window.close() | |
window = sg.Window('ADMIN Account Page', Admin_layout) # proceeds to the admin page | |
# -------------------------------------------------------------------------------------- | |
# This is another feature of PySimpleGUI, where you can create a layout dynamically | |
# as you iterate through a loop | |
# Because i don't know how many accounts the user will create, | |
# the program opens the pickled file, saves it in a list (accs) and for every element | |
# of the list, it adds a line to the layout containing the username of each account | |
# -------------------------------------------------------------------------------------- | |
while True: | |
event, values = window.read() # added a simple functionality | |
if event in (sg.Button, 'Print all users'): # to the admin account | |
window.close() # where he can print all the users | |
layout = [[sg.Text('USER ACCOUNTS')]] # I would like to add the other 2 | |
for i in range(len(accs)): # functional buttons in the admin account | |
row_layout = [sg.Text(accs[i][0])] # if time allows it, but it is not | |
layout += [row_layout] # a priority | |
layout += [[sg.Button('Ok')]] | |
window = sg.Window('ACCOUNTS', layout) | |
while True: | |
event, values = window.read() | |
if event in (sg.Button, 'Ok'): | |
window.close() # One bug i haven't found a way to work around | |
break # is when the user presses 'Ok' in the popup | |
if event is None: # window, the program doesn't stop completetly | |
window.close() # even though the window closes | |
break | |
# -------------------------------------------------------------------------- | |
# For the management account i think the functionality would revolve around | |
# stock management, so i can't add any more functionality to it | |
# -------------------------------------------------------------------------- | |
if accs[i][0][0] == 'm': | |
match = True | |
window.close() | |
window = sg.Window('Management Page', Mod_layout) | |
while True: | |
event, values = window.read() | |
if event is None: | |
window.close() | |
break | |
if event in (sg.Button, 'Edit Stock'): | |
sg.Popup('You can edit the Stock entries') | |
if event in (sg.Button, 'Order Supplies'): | |
sg.Popup('New Supplies have been ordered') | |
if event in (sg.Button, 'Manage Clients'): | |
sg.Popup('You can edit the clients database') | |
if event in (sg.Button, 'Manage Shipments'): | |
sg.Popup('You can control the shipping process') | |
break | |
# -------------------------------------------------------------------- | |
# Public accounts also don't allow much to the user, except previewing | |
# the stock, so not much i can do about that function either | |
# -------------------------------------------------------------------- | |
if accs[i][0][0] == 'p': # user is a guest | |
match = True | |
window.close() | |
window = sg.Window('Guest Page', Public_layout) | |
while True: | |
event, values = window.read() | |
if event is None: | |
window.close() | |
break | |
if event in (sg.Button, 'View Stock'): | |
sg.Popup("A short preview of the company's stock") | |
break | |
if (values[0] == accs[i][0]) & (values[1] != accs[i][1]): # if the username is correct | |
u_match = True # but the password is wrong | |
sg.Popup("Wrong password") | |
# When there is no match with the file the program is reading, this part of the code is read | |
# | |
else: | |
print(i) # console debugging | |
print(len(accs)) # // | |
if (i <= len(accs) - 1) & (not match): # if the the whole file is read | |
match = False # and no match is found | |
if (i == len(accs)) & u_match: # if the user provides the correct username, but not password | |
i = 0 # the loop resets until correct password is entered | |
if not match and not u_match: # case where user doesnt exist in the file | |
sg.Popup("User doesn't exist") | |
else: | |
window.close() | |
break | |
######################################################################################################################### |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment