Skip to content

Instantly share code, notes, and snippets.

@quirksubdol
Last active October 31, 2019 21:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quirksubdol/8390e53e70db2c03cb05ecf22408ca1e to your computer and use it in GitHub Desktop.
Save quirksubdol/8390e53e70db2c03cb05ecf22408ca1e to your computer and use it in GitHub Desktop.
# ---------------------------------------------------------------------------------------------------------------------- #
# 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