From 7edf2f62af1ad14a2eaa6a54f6d713d6e32a1061 Mon Sep 17 00:00:00 2001 From: Navdeep Gill Date: Sat, 9 Jun 2018 16:41:01 -0700 Subject: [PATCH 1/9] Mongo furniture activity. Lesson 8 Activity --- .../lesson8Activity/mongo_furniture.py | 45 +++++++++++++++ students/navdeep/session18/mongo_furniture.py | 56 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 students/navdeep/session18/lesson8Activity/mongo_furniture.py create mode 100644 students/navdeep/session18/mongo_furniture.py diff --git a/students/navdeep/session18/lesson8Activity/mongo_furniture.py b/students/navdeep/session18/lesson8Activity/mongo_furniture.py new file mode 100644 index 00000000..826ff717 --- /dev/null +++ b/students/navdeep/session18/lesson8Activity/mongo_furniture.py @@ -0,0 +1,45 @@ +""" +Mongodb #1 +test and learn mongodb +""" +import pymongo +import logging +from connect_mongodb import * +#from connect_mongodb import * + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) +logger.info('Setup the connection to mongodb') +def main(): + with connect_mongodb.login_mongodb_cloud() as client: + + logger.info('We are going to use a database called dev') + db = client['dev'] + logger.info('And in that database create a collection called furniture') + furniture = db['furniture'] + logger.info('Now we add data from the dictionary') + results = furniture.insert_many([ + { + 'product': {'product_type': 'couch', 'color': 'red'}, + 'in_stock_quantity': 10 + }, + { + 'product': {'product_type': 'couch', 'color':'blue'}, + 'in_stock_quantity': 3 + }, + { + 'product':{'product_type': 'table', 'color':'brown'}, + 'in_stock_quantity':17 + }, + { + 'product':{'product_type': 'chair', 'color': 'green'}, + 'in_stock_quantity': 4 + }]) + + logger.info('Find the table products and their colors') + query_couch = {'product.product_type': 'couch'} + results = furniture.find_one(query_couch, {'product.color': 'red'}) + print(results) + +if __name__ == '__main__': + main() diff --git a/students/navdeep/session18/mongo_furniture.py b/students/navdeep/session18/mongo_furniture.py new file mode 100644 index 00000000..d2d56949 --- /dev/null +++ b/students/navdeep/session18/mongo_furniture.py @@ -0,0 +1,56 @@ +""" +Mongodb #1 +test and learn mongodb +""" +import pymongo +import logging +#from connect_mongodb import * + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) +logger.info('Setup the connection to mongodb') +def main(): + with login_mongodb_cloud() as client: + + logger.info('We are going to use a database called dev') + db = client['dev'] + logger.info('And in that database create a collection called furniture') + furniture = db['furniture'] + logger.info('Now we add data from the dictionary') + results = furniture.insert_many([ + { + 'product': {'product_type': 'couch', 'color': 'red'}, + 'in_stock_quantity': 10 + }, + { + 'product': {'product_type': 'couch', 'color':'blue'}, + 'in_stock_quantity': 3 + }, + { + 'product':{'product_type': 'table', 'color':'brown'}, + 'in_stock_quantity':17 + }, + { + 'product':{'product_type': 'chair', 'color': 'green'}, + 'in_stock_quantity': 4 + }]) + + logger.info('Find the table products and their colors') + query_couch = {'product.product_type': 'couch'} + results = furniture.find_one(query_couch, {'product.color': 'red'}) + print(results) + +def login_mongodb_cloud(): + """ + connect to mongodb and login + """ + logging.basicConfig(level=logging.INFO) + log = logging.getLogger(__name__) + log.info('Here is where we use the connect to mongodb.') + log.info('Note use of f string to embed the user & password (from the tuple).') + client = pymongo.MongoClient('mongodb://navgill:python@cluster0-shard-00-00-r6qke.mongodb.net:27017,cluster0-shard-00-01-r6qke.mongodb.net:27017,cluster0-shard-00-02-r6qke.mongodb.net:27017/test?ssl=true&replicaSet=Cluster0-shard-0&authSource=admin&retryWrites=true') + #config.read(config_file) + return client + +if __name__ == '__main__': + main() From f9953720a0be1f4b854e698b9ceddd75591c05d7 Mon Sep 17 00:00:00 2001 From: Navdeep Gill Date: Sat, 9 Jun 2018 16:48:01 -0700 Subject: [PATCH 2/9] Redis furniture activity. Lesson 8 Activity --- .../lesson8Activity/redis_furniture.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 students/navdeep/session18/lesson8Activity/redis_furniture.py diff --git a/students/navdeep/session18/lesson8Activity/redis_furniture.py b/students/navdeep/session18/lesson8Activity/redis_furniture.py new file mode 100644 index 00000000..6396a4c4 --- /dev/null +++ b/students/navdeep/session18/lesson8Activity/redis_furniture.py @@ -0,0 +1,45 @@ +import logging +import redis +from connnect_redis import * + + +logging.basicConfig(level = logging.INFO) +log = logging.getLogger(__name__) +def main(): + log.info('Step 1: connect to Redis') + r = connnect_redis.login_redis_cloud() + log.info('Step 2: cache some data in Redis') + r.delete('Andy') + r.delete('Navdeep') + r.delete('Lorenzo') + r.delete('Nick') + r.delete('Kaleb') + r.delete('Torin') + r.set('Andy', {'email':'andy@somewhere.com', 'phone': '123-456-7890', 'zip': + '98102'}) + r.rpush('186675', 'chair') + r.rpush('186675', 'red') + r.rpush('186675', 'leather') + r.rpush('186675', '5.99') + r.hmset('Navdeep', {'email':'nav@somewhere.com', 'phone':'456-123-7890','zip':'98105'}) + r.hmset('Lorenzo',{'email':'enzo@somewhere.com', 'phone':'789-123-4560', 'zip':'98115'}) + r.hmset('Nick', {'email':':nick@somewhere.com', 'phone':'423-156-7890', 'zip':'98105'}) + r.hmset('Kaleb', {'email':'ksmith@somewhere.com','phone': '178-123-7890', 'zip':'98007'}) + r.hmset('Torin', {'email':'torin@somewhere.com', 'phone':'012-781-4567', 'zip':'98111'}) + log.info('Step 2: now I can read it') + customer_one = r.get('Andy') + log.info('But I must know the key') + print(customer_one) + #element = r.lindex('user2', 0) + #element = str(element) + #element = int(element) + r.delete('Andy') + Nav_Email = r.hget('Navdeep', 'email') + Nav_Zip = r.hget('Navdeep', 'zip') + Nav_Phone = r.hget('Navdeep', 'phone') + print(Nav_Email) + print(Nav_Zip) + print(Nav_Phone) + +if __name__ == '__main__': + main() \ No newline at end of file From f39a600aa791b5f66f875f413d1da2e46a65eaec Mon Sep 17 00:00:00 2001 From: Navdeep Gill Date: Sat, 9 Jun 2018 16:48:20 -0700 Subject: [PATCH 3/9] Neo4j activity. Lesson 8 Activity --- .../lesson8Activity/neo4j_furniture.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 students/navdeep/session18/lesson8Activity/neo4j_furniture.py diff --git a/students/navdeep/session18/lesson8Activity/neo4j_furniture.py b/students/navdeep/session18/lesson8Activity/neo4j_furniture.py new file mode 100644 index 00000000..f7e8fb91 --- /dev/null +++ b/students/navdeep/session18/lesson8Activity/neo4j_furniture.py @@ -0,0 +1,64 @@ +""" + neo4j example +""" +from neo4j.v1 import GraphDatabase, basic_auth +import logging + +logging.basicConfig(level = logging.INFO) +log = logging.getLogger(__name__) +def main(): + log.info('Here is where we use the connect to neo4j.') + log.info('') + graphenedb_user = input("Username: ") + graphenedb_pass = input("Password: ") + graphenedb_url = input("URL: ") + driver = GraphDatabase.driver(graphenedb_url.strip(), + auth=basic_auth(graphenedb_user.strip(), graphenedb_pass.strip())) + with driver.session() as session: + log.info('Adding a few Person nodes') + for first, last in [('Bob', 'Jones'), + ('Nancy', 'Cooper'), + ('Alice', 'Cooper'), + ('Fred', 'Barnes'), + ('Mary', 'Evans'), + ('Marie', 'Curie'), + ]: + cyph = "CREATE (n:Person {first_name:'%s', last_name: '%s'})" % ( + first, last) + session.run(cyph) + + log.info("Get all of people in the DB:") + cyph = """MATCH (p:Person) + RETURN p.first_name as first_name, p.last_name as last_name + """ + result = session.run(cyph) + print("People in database:") + for record in result: + print(record['first_name'], record['last_name']) + + favorite_colors = ['blue', 'orange', 'green', 'purple', 'gold'] + for color in favorite_colors: + cyph = "CREATE (n:Color {color: '%s'})" % (color) + session.run(cyph) + cypher = """ + MATCH (p1:Person {first_name: 'Alice', last_name: 'Cooper'}), (c1:Color {color: 'orange'}) + CREATE (p1)-[c:FAVORITE_COLOR]->(c1) + return p1 + """ + session.run(cypher) + + cypher = """ + MATCH (p1:Person {first_name: 'Bob', last_name: 'Jones'}), (c1:Color {color: 'blue'}) + CREATE (p1)-[c:FAVORITE_COLOR]->(c1) + return p1 + """ + session.run(cypher) + cypher = """ + MATCH (p1:Person {first_name: 'Fred', last_name: 'Barnes'}), (c1:Color {color: 'gold'}) + CREATE (p1)-[c:FAVORITE_COLOR]->(c1) + return p1 + """ + session.run(cypher) + session.close() + +main() \ No newline at end of file From ab02063ce1081878f8001b7318287e5ef0069c4f Mon Sep 17 00:00:00 2001 From: Navdeep Gill Date: Sat, 9 Jun 2018 17:06:29 -0700 Subject: [PATCH 4/9] Menu for mongo mailroom. Assignment 8 --- .../mailroom_database_menu_mongo.py | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 students/navdeep/session18/mailroom_nosql/mailroom_database_menu_mongo.py diff --git a/students/navdeep/session18/mailroom_nosql/mailroom_database_menu_mongo.py b/students/navdeep/session18/mailroom_nosql/mailroom_database_menu_mongo.py new file mode 100644 index 00000000..55558ac8 --- /dev/null +++ b/students/navdeep/session18/mailroom_nosql/mailroom_database_menu_mongo.py @@ -0,0 +1,192 @@ +import os.path +from populate_mailroom_nosql import ManipulateDBMongo + +def initializeOptionsDB(): + """ + Initializes the options the user can select from. A dictionary where the key is the option the user can select and the values are the functions that are called based off of the user's selection + :return: The options dictionary. + """ + options_dict = {'t': askUserForDonor, 's': writeToFile, 'r': createReport, 'd': delete_instance, 'e': exitMessage} + return options_dict + +def displayMenu(): + """ + displays the menu of options to the user + """ + str_menu = "\n1. Type 't' to add a name, donation and thank you card\n"+\ + "2. Type 'r' to Create a Report and see a list of the donors\n"+\ + "3. Type 's' to Send letters to everyone\n"+\ + "4. Type 'd' to delete a donor and their donations\n"+\ + "5. Type 'e' to exit the program\n" + #for testing purposes to determine menu is returned correctly + #return str_menu + print(str_menu) + +def menu(donor_collection_obj, menu_dict): + """ + This function will print out a menu of options for the user to choose from, + ask the user what action they would like to perform and then call the function that performs that action + :param donor_collection_obj: The database of donor objects + :param menu_dict: The dictionary of user options + """ + user_option = "" + while user_option.lower() != 'e': + displayMenu() + user_option = input("Select an option from the menu: ") + user_option = user_option.lower().strip() + #user_option = 't' #for testing purposes + #return user_option #used to test menu produces correct user input + try: + menu_dict[user_option](donor_collection_obj) + except KeyError as e: + print(e) + print("Invalid option selected. Please try again") + +def askUserForDonor(donor_collection_obj): + """ + Allows user to add a new donor object to the database or print out + the names of the current donors or exit back to the main menu. + The user can also type in the name of a donor that already + exists to append a new donation to that donor object + :param donor_collection_obj: the database of donor objects + """ + user_donor_option = "" + while user_donor_option != 'Exit': + user_donor_option = input("1. Type 'New' of a new donor\n" + "2. Type 'List' to list the donor names\n" + "3. Type 'Exit' to return to main menu\n" + "\nYour Selection: ") + + user_donor_option = clean_text(user_donor_option) + if user_donor_option == 'New': + addNewDonor(donor_collection_obj) + elif user_donor_option == 'List': + showDonorNames(donor_collection_obj) + elif user_donor_option == 'Exit': + return + else: + print("Please select a valid option:") + print() + +def addNewDonor(donor_collection_obj): + """ + Prompts the user for a first name, last name, email for the donor object, regardless of whether or not the donor currently exists. The user cannot enter in a blank string as a name. + :param donor_collection_obj: The database of donor objects + """ + first_name = None + last_name = None + email = None + invalid = True + while invalid == True: + try: + first_name = input("Enter first name for donor: ") + last_name = input("Enter last name for donor: ") + email = input("Enter email for donor: ") + if first_name == "" or last_name == "" or email == "": + raise ValueError + except ValueError as e: + print("The name you entered is invalid. Enter proper first/last name") + else: + first_name, last_name = clean_text(first_name), clean_text(last_name) + email = email.strip() + invalid = False + addNewDonation(donor_collection_obj, first_name, last_name, email) + +def addNewDonation(donor_collection_obj, first_name, last_name, email): + """ + Allows the user to input a new donation for the user. The user must + enter a valid amount (integer or float). The user must + also enter a value greater than 0. If the donor currently exists + in the dictionary, the donor's new donation will be appended to the list stored under their name, which is the key in the dictionary. If the donor does not exist in the database, a new donor object will be created + :param donor_collection_obj: the database of donor objects + :param first_name: first name of the new donor, a string + :param last_name: last name of the new donor + """ + new_donation = getUserValue("Donation Amount") + donor_collection_obj.add_donor_mongo(first_name, last_name, email, new_donation) + print(donor_collection_obj.thank_you_message(first_name, new_donation)) + +def getUserValue(str_reason = "value"): + """ + This function will ask the user for a numeric value. This function is used when the user is entering in a new donation amount, entering a factor they would like to multiply the current donations by or setting the boundary for the specific donations they want to factor. + :param str_reason: The reason why the user is being asked to enter in a number. For example, str_reason will equal "donation" when the user is supposed to enter in a new donation amount. + :return: Returns the value the user entered + """ + invalid = True + while invalid == True: + try: + user_value = float(input("Enter number for {}: ".format(str_reason))) + if type(user_value) != float or user_value < 1: + raise ValueError + except ValueError: + print("\nThe value you entered was illegal\n") + else: + invalid = False + return user_value + +def clean_text(name): + """ + Eliminates text of whitespace, lowercase all letters and capitalize the first letter + """ + name = name.strip() + name = name.lower() + name = name.title() + return name + +def delete_instance(donor_collection_obj): + invalid = True + while invalid == True: + try: + del_email = input("Enter email of donor you would like to delete: ") + if del_email == "" or not donor_collection_obj.donor_exists_mongo(del_email): + raise ValueError + except ValueError: + print("\nEmail does not exist in database.\n") + else: + invalid = False + donor_collection_obj.delete_donation_mongo(del_email) + + + +def showDonorNames(donor_collection_obj): + """ + Prints out the full names of each donor + :param donor_collection_obj: The database of donors + """ + print(donor_collection_obj.show_donors()) + + +def writeToFile(donor_collection_obj): + """ + Allows user to save a letter written to each donor and their donation amounts to the current working directory + :param donor_collection_obj: The database of donor objects + """ + donor_collection_obj.write_to_file() + +def createReport(donor_collection_obj): + """ + Allows user to create a report that shows each donor's name, total donated, number of times donated and average donations. This function calls the donor collection objects create report method, which generates the report. + :param donor_collection_obj: The database of donor objects + """ + report_header() + print(donor_collection_obj.create_report()) + +def report_header(): + str_header = ('\n{:25s} | {:25s} | {:11s} | {:9s} | {:12s}'.format("Donor Name", "Donor Email", "Total Given", "Num Gifts", "Average Gift")) + str_header = str_header + '\n' + ("-"*95) + print(str_header) + +def exitMessage(donor_collection_obj): + """ + Exit message once the user decides to end the entire program + All of the donors stored in the donor_collection object will be printed + a final time + :param donor_collection_obj:The database of donor objects + """ + print("\nThank you to the following donors for all of your donations: \n") + showDonorNames(donor_collection_obj) + print("\nCome back anytime to donate more!") + +store_donors = ManipulateDBMongo() +menu_dict = initializeOptionsDB() +menu(store_donors, menu_dict) From 3a91d2e6537816c3f447e7d0abff96dc621d5ffc Mon Sep 17 00:00:00 2001 From: Navdeep Gill Date: Sat, 9 Jun 2018 17:07:13 -0700 Subject: [PATCH 5/9] Menu for redis mailroom. Assignment 8 --- .../mailroom_database_menu_redis.py | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 students/navdeep/session18/mailroom_nosql/mailroom_database_menu_redis.py diff --git a/students/navdeep/session18/mailroom_nosql/mailroom_database_menu_redis.py b/students/navdeep/session18/mailroom_nosql/mailroom_database_menu_redis.py new file mode 100644 index 00000000..261f6eb5 --- /dev/null +++ b/students/navdeep/session18/mailroom_nosql/mailroom_database_menu_redis.py @@ -0,0 +1,192 @@ +import os.path +from populate_mailroom_redis import ManipulateDBRedis + +def initializeOptionsDB(): + """ + Initializes the options the user can select from. A dictionary where the key is the option the user can select and the values are the functions that are called based off of the user's selection + :return: The options dictionary. + """ + options_dict = {'t': askUserForDonor, 's': writeToFile, 'r': createReport, 'd': delete_instance, 'e': exitMessage} + return options_dict + +def displayMenu(): + """ + displays the menu of options to the user + """ + str_menu = "\n1. Type 't' to add a name, donation and thank you card\n"+\ + "2. Type 'r' to Create a Report and see a list of the donors\n"+\ + "3. Type 's' to Send letters to everyone\n"+\ + "4. Type 'd' to delete a donor and their donations\n"+\ + "5. Type 'e' to exit the program\n" + #for testing purposes to determine menu is returned correctly + #return str_menu + print(str_menu) + +def menu(donor_collection_obj, menu_dict): + """ + This function will print out a menu of options for the user to choose from, + ask the user what action they would like to perform and then call the function that performs that action + :param donor_collection_obj: The database of donor objects + :param menu_dict: The dictionary of user options + """ + user_option = "" + while user_option.lower() != 'e': + displayMenu() + user_option = input("Select an option from the menu: ") + user_option = user_option.lower().strip() + #user_option = 't' #for testing purposes + #return user_option #used to test menu produces correct user input + try: + menu_dict[user_option](donor_collection_obj) + except KeyError as e: + print(e) + print("Invalid option selected. Please try again") + +def askUserForDonor(donor_collection_obj): + """ + Allows user to add a new donor object to the database or print out + the names of the current donors or exit back to the main menu. + The user can also type in the name of a donor that already + exists to append a new donation to that donor object + :param donor_collection_obj: the database of donor objects + """ + user_donor_option = "" + while user_donor_option != 'Exit': + user_donor_option = input("1. Type 'New' of a new donor\n" + "2. Type 'List' to list the donor names\n" + "3. Type 'Exit' to return to main menu\n" + "\nYour Selection: ") + + user_donor_option = clean_text(user_donor_option) + if user_donor_option == 'New': + addNewDonor(donor_collection_obj) + elif user_donor_option == 'List': + showDonorNames(donor_collection_obj) + elif user_donor_option == 'Exit': + return + else: + print("Please select a valid option:") + print() + +def addNewDonor(donor_collection_obj): + """ + Prompts the user for a first name, last name, email for the donor object, regardless of whether or not the donor currently exists. The user cannot enter in a blank string as a name. + :param donor_collection_obj: The database of donor objects + """ + first_name = None + last_name = None + email = None + invalid = True + while invalid == True: + try: + first_name = input("Enter first name for donor: ") + last_name = input("Enter last name for donor: ") + email = input("Enter email for donor: ") + if first_name == "" or last_name == "" or email == "": + raise ValueError + except ValueError as e: + print("The name you entered is invalid. Enter proper first/last name") + else: + first_name, last_name = clean_text(first_name), clean_text(last_name) + email = email.strip() + invalid = False + addNewDonation(donor_collection_obj, first_name, last_name, email) + +def addNewDonation(donor_collection_obj, first_name, last_name, email): + """ + Allows the user to input a new donation for the user. The user must + enter a valid amount (integer or float). The user must + also enter a value greater than 0. If the donor currently exists + in the dictionary, the donor's new donation will be appended to the list stored under their name, which is the key in the dictionary. If the donor does not exist in the database, a new donor object will be created + :param donor_collection_obj: the database of donor objects + :param first_name: first name of the new donor, a string + :param last_name: last name of the new donor + """ + new_donation = getUserValue("Donation Amount") + donor_collection_obj.add_donor_redis(first_name, last_name, email, new_donation) + print(donor_collection_obj.thank_you_message(first_name, new_donation)) + +def getUserValue(str_reason = "value"): + """ + This function will ask the user for a numeric value. This function is used when the user is entering in a new donation amount, entering a factor they would like to multiply the current donations by or setting the boundary for the specific donations they want to factor. + :param str_reason: The reason why the user is being asked to enter in a number. For example, str_reason will equal "donation" when the user is supposed to enter in a new donation amount. + :return: Returns the value the user entered + """ + invalid = True + while invalid == True: + try: + user_value = float(input("Enter number for {}: ".format(str_reason))) + if type(user_value) != float or user_value < 1: + raise ValueError + except ValueError: + print("\nThe value you entered was illegal\n") + else: + invalid = False + return user_value + +def clean_text(name): + """ + Eliminates text of whitespace, lowercase all letters and capitalize the first letter + """ + name = name.strip() + name = name.lower() + name = name.title() + return name + +def delete_instance(donor_collection_obj): + invalid = True + while invalid == True: + try: + del_email = input("Enter email of donor you would like to delete: ") + if del_email == "" or not donor_collection_obj.donor_exists_redis(del_email): + raise ValueError + except ValueError: + print("\nEmail does not exist in database.\n") + else: + invalid = False + donor_collection_obj.delete_donation_redis(del_email) + + + +def showDonorNames(donor_collection_obj): + """ + Prints out the full names of each donor + :param donor_collection_obj: The database of donors + """ + print(donor_collection_obj.show_donors()) + + +def writeToFile(donor_collection_obj): + """ + Allows user to save a letter written to each donor and their donation amounts to the current working directory + :param donor_collection_obj: The database of donor objects + """ + donor_collection_obj.write_to_file() + +def createReport(donor_collection_obj): + """ + Allows user to create a report that shows each donor's name, total donated, number of times donated and average donations. This function calls the donor collection objects create report method, which generates the report. + :param donor_collection_obj: The database of donor objects + """ + report_header() + print(donor_collection_obj.create_report()) + +def report_header(): + str_header = ('\n{:25s} | {:25s} | {:11s} | {:9s} | {:12s}'.format("Donor Name", "Donor Email", "Total Given", "Num Gifts", "Average Gift")) + str_header = str_header + '\n' + ("-"*95) + print(str_header) + +def exitMessage(donor_collection_obj): + """ + Exit message once the user decides to end the entire program + All of the donors stored in the donor_collection object will be printed + a final time + :param donor_collection_obj:The database of donor objects + """ + print("\nThank you to the following donors for all of your donations: \n") + showDonorNames(donor_collection_obj) + print("\nCome back anytime to donate more!") + +store_donors = ManipulateDBRedis() +menu_dict = initializeOptionsDB() +menu(store_donors, menu_dict) From 8c3e8ca5feec2caef5468be301108e6948c28f13 Mon Sep 17 00:00:00 2001 From: Navdeep Gill Date: Sat, 9 Jun 2018 17:14:27 -0700 Subject: [PATCH 6/9] Class to manipulate mongo database with mailroom information. Assignment 8 --- .../mailroom_nosql/populate_mailroom_nosql.py | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 students/navdeep/session18/mailroom_nosql/populate_mailroom_nosql.py diff --git a/students/navdeep/session18/mailroom_nosql/populate_mailroom_nosql.py b/students/navdeep/session18/mailroom_nosql/populate_mailroom_nosql.py new file mode 100644 index 00000000..6cc21131 --- /dev/null +++ b/students/navdeep/session18/mailroom_nosql/populate_mailroom_nosql.py @@ -0,0 +1,162 @@ +import connect_mongodb +import os + + +class ManipulateDBMongo(object): + def __init__(self): + self.mongodb = connect_mongodb.login_mongodb_cloud() + + def add_donor_mongo(self, new_first_name, new_last_name, new_email, donation_amount): + """ + Ability to add a new donor to the mongo database or if the donor exists, we can still add a new donation + """ + if not self.donor_exists_mongo(new_email): + with self.mongodb as client: + db = client['dev'] + mailroom = db['mailroom'] + try: + mailroom.insert({'email': new_email, 'first_name': new_first_name, 'last_name': new_last_name, 'full_name': new_first_name + ' ' + new_last_name, 'donations': [donation_amount]}) + except Exception as e: + print(f'Error creating = {new_email}') + print(e) + client.close() + else: + self.add_donation_mongo(new_email, donation_amount) + + def add_donation_mongo(self, email, donation_amount): + """ + Adds a new donation to database + """ + with self.mongodb as client: + db = client['dev'] + mailroom = db['mailroom'] + try: + mailroom.update({'email':email}, {'$push':{'donations':donation_amount}}) + except Exception as e: + print(f'Error creating = {email}') + print(e) + client.close() + + def thank_you_message(self, name, donation_amount): + """ + Creates thank you message for donor + """ + thank_you_message = "\nThank you {0:s} for you generous donation of ${1:.2f}.\n".format(name, round(donation_amount,2)) + return thank_you_message + + def delete_donation_mongo(self, del_email): + """ + Ability to delete donors and their donations + """ + with self.mongodb as client: + db = client['dev'] + mailroom = db['mailroom'] + try: + mailroom.remove({"email": {"$eq": del_email}}) + print("{} has been removed from the database\n".format(del_email)) + except Exception as e: + print(f'Error deleting = {email}') + print(e) + + def donor_exists_mongo(self, find_email): + """ + Determines if donor already exists in database + """ + current_donor = False + with self.mongodb as client: + db = client['dev'] + mailroom = db['mailroom'] + try: + query = {'email': find_email} + results = mailroom.find_one(query) + if results: + current_donor = True + except Exception as e: + print(f'Error occurred. See below') + print(e) + client.close() + return current_donor + + def create_report(self): + """ + Create Report using Mongo queries + """ + str_build = "" + with self.mongodb as client: + db = client['dev'] + mailroom = db['mailroom'] + try: + for donor in mailroom.find(): + num_donations = self.num_donations(donor['donations']) + sum_donations = self.sum_donations(donor['donations']) + str_build += "{:25s} {:25s} {:11.2f} {:9.2f} {:12.2f}\n".format(donor['full_name'], donor['email'], num_donations, sum_donations , (sum_donations / num_donations)) + except Exception as e: + print('Error occurred. See Below.') + print(e) + print('\n') + client.close() + return str_build + + def sum_donations(self, donation_list): + """ + Sums a donors donations + """ + return sum(donation_list) + + def num_donations(self, donation_list): + """ + Returns the number of donations a donor has given + """ + return len(donation_list) + + def write_to_file(self): + """ + Writes to a file. The donors name and total donations will be stored in the contents of the file, while the file name will be the donors email address + """ + with self.mongodb as client: + db = client['dev'] + mailroom = db['mailroom'] + try: + file_name = None + donor_file_name = None + full_file_name = None + complete_file_name = None + for donor in mailroom.find(): + donor_file_name = donor['email'] + total_donations = sum(donor['donations']) + donor_full_name = donor['full_name'] + full_file_name = "{}.txt".format(donor_file_name) + complete_file_name = os.path.join(os.getcwd(), full_file_name) + letter = self.letter_to_file(donor_full_name,total_donations) + with open(complete_file_name, 'w+') as f: + f.write(letter) + except Exception as e: + print("Error occurred. See below") + print(e) + print('\n') + client.close() + + def letter_to_file(self, donor, donations): + str_letter = "Dear {},\n\tThank you for your kind donation(s) of {}.\n\tIt will be put to very good use.\n\t\tSincerely,\n\t\t\t-The Team".format(donor, str(donations)) + return str_letter + + def show_donors(self): + """ + Lists the donor names + """ + with self.mongodb as client: + db = client['dev'] + mailroom = db['mailroom'] + str_build = "" + try: + for donor in mailroom.find(): + str_build += donor['full_name'] + ' -- ' + donor['email'] +'\n' + except Exception as e: + print(f'Error occured. See below') + print(e) + client.close() + return str_build + + + + From 92915cac2611ff1013b76dd6316e298a298ddbea Mon Sep 17 00:00:00 2001 From: Navdeep Gill Date: Sat, 9 Jun 2018 17:14:56 -0700 Subject: [PATCH 7/9] Class to manipulate redis database with mailroom information. Assignment 8 --- .../mailroom_nosql/populate_mailroom_redis.py | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 students/navdeep/session18/mailroom_nosql/populate_mailroom_redis.py diff --git a/students/navdeep/session18/mailroom_nosql/populate_mailroom_redis.py b/students/navdeep/session18/mailroom_nosql/populate_mailroom_redis.py new file mode 100644 index 00000000..bb0e1c6b --- /dev/null +++ b/students/navdeep/session18/mailroom_nosql/populate_mailroom_redis.py @@ -0,0 +1,143 @@ +import connnect_redis +import os + + +class ManipulateDBRedis(object): + def __init__(self): + self.redisdb = connnect_redis.login_redis_cloud() + + def add_donor_redis(self, new_first_name, new_last_name, new_email, donation_amount): + """ + Ability to add a new donor to the mongo database or if the donor exists, we can still add a new donation + """ + transaction_id = new_email + '_1' + if not self.donor_exists_redis(new_email): + try: + full_name = new_first_name + ' ' + new_last_name + self.redisdb.rpush(new_email, full_name) + self.redisdb.rpush(new_email, donation_amount) + except Exception as e: + print(f'Error creating = {new_email}') + print(e) + else: + self.add_donation_redis(new_email, donation_amount) + + def add_donation_redis(self, email, donation_amount): + """ + Adds a new donation to database + """ + try: + self.redisdb.rpush(email, donation_amount) + except Exception as e: + print(f'Error adding donation to: {email}') + print(e) + + def thank_you_message(self, name, donation_amount): + """ + Creates thank you message for donor + """ + thank_you_message = "\nThank you {0:s} for you generous donation of ${1:.2f}.\n".format(name, round(donation_amount,2)) + return thank_you_message + + def delete_donation_redis(self, del_email): + """ + Ability to delete donors and their donations + """ + try: + self.redisdb.delete(del_email) + print("{} has been removed from the database\n".format(del_email)) + except Exception as e: + print(f'Error deleting = {email}') + print(e) + + def donor_exists_redis(self, find_email): + """ + Determines if donor already exists in database + """ + current_donor = False + try: + for key in self.redisdb.keys(): + if key == find_email: + current_donor = True + except Exception as e: + print(f'Error occurred. See below') + print(e) + return current_donor + + def create_report(self): + """ + Create Report using Mongo queries + """ + str_build = "" + try: + for donor in self.redisdb.keys(): + num_donation = self.num_donations(donor) + sum_donation = self.sum_donations(donor) + str_build += "{:25s} {:25s} {:11.2f} {:9.2f} {:12.2f}\n".format(self.redisdb.lindex(donor, 0), donor, num_donation, sum_donation , (sum_donation / num_donation)) + except Exception as e: + print('Error occurred. See Below.') + print(e) + print('\n') + return str_build + + def sum_donations(self, donor_email): + """ + Sums a donors donations + """ + sum_list = 0 + element = None + for index in range(1, self.redisdb.llen(donor_email)): + element = self.redisdb.lindex(donor_email, index) + element = str(element) + element = float(element.strip()) + sum_list += element + return sum_list + + def num_donations(self, donor_email): + """ + Returns the number of donations a donor has given + """ + return self.redisdb.llen(donor_email) - 1 + + def write_to_file(self): + """ + Writes to a file. The donors name and total donations will be stored in the contents of the file, while the file name will be the donors email address + """ + try: + file_name = None + donor_file_name = None + full_file_name = None + complete_file_name = None + for donor in self.redisdb.keys(): + donor_file_name = donor + total_donations = self.sum_donations(donor) + donor_full_name = self.redisdb.lindex(donor, 0) + full_file_name = "{}.txt".format(donor_file_name) + complete_file_name = os.path.join(os.getcwd(), full_file_name) + letter = self.letter_to_file(donor_full_name,total_donations) + with open(complete_file_name, 'w+') as f: + f.write(letter) + except Exception as e: + print("Error occurred. See below") + print(e) + print('\n') + + def letter_to_file(self, donor, donations): + str_letter = "Dear {},\n\tThank you for your kind donation(s) of {}.\n\tIt will be put to very good use.\n\t\tSincerely,\n\t\t\t-The Team".format(donor, str(donations)) + return str_letter + + def show_donors(self): + """ + Lists the donor names + """ + str_build = "" + try: + for donor_email in self.redisdb.keys(): + str_build += self.redisdb.lindex(donor_email, 0) + ' -- ' + donor_email +'\n' + except Exception as e: + print() + return str_build + + + + From f0b475bb003397e052599ce733048f52d5b6e77e Mon Sep 17 00:00:00 2001 From: Navdeep Gill Date: Sat, 9 Jun 2018 17:17:43 -0700 Subject: [PATCH 8/9] Class to manipulate neo4j database with mailroom information. Assignment 8 --- .../mailroom_nosql/populate_mailroom_neo4j.py | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 students/navdeep/session18/mailroom_nosql/populate_mailroom_neo4j.py diff --git a/students/navdeep/session18/mailroom_nosql/populate_mailroom_neo4j.py b/students/navdeep/session18/mailroom_nosql/populate_mailroom_neo4j.py new file mode 100644 index 00000000..3940ce54 --- /dev/null +++ b/students/navdeep/session18/mailroom_nosql/populate_mailroom_neo4j.py @@ -0,0 +1,133 @@ +from neo4j.v1 import GraphDatabase, basic_auth +import os + + +class ManipulateDBNeo(object): + def __init__(self, user, password, url): + self.driver = GraphDatabase.driver(url.strip(), + auth=basic_auth(user.strip(), password.strip())) + + def add_donor_neo(self, new_first_name, new_last_name, new_email, donation_amount): + """ + Ability to add a new donor to the neo database or if the donor exists, we can still add a new donation + """ + with self.driver.session() as session: + transaction_id = new_email + '_1' + if not self.donor_exists_neo(new_email, session): + try: + full_name = new_first_name + ' ' + new_last_name + cyph = "CREATE (n:Donor {email:'%s', first_name:'%s',last_name:'%s', full_name:'%s'})" % (new_email, new_first_name, new_last_name, full_name) + session.run(cyph) + except Exception as e: + print(f'Error creating = {new_email}') + print(e) + else: + self.add_donation_neo(new_email, donation_amount) + + def add_donation_neo(self, email, donation_amount): + """ + Adds a new donation to database + """ + with self.driver.session() as session: + try: + cyph = """ + MATCH (d1:Donor {email: '%s'}) + CREATE (d1)-[donate:DONATION]->({donation_amount: '%s'}) + RETURN d1 + """ % (email, donation_amount) + session.run(cyph) + except Exception as e: + print(f'Error adding donation to: {email}') + print(e) + + def thank_you_message(self, name, donation_amount): + """ + Creates thank you message for donor + """ + thank_you_message = "\nThank you {0:s} for you generous donation of ${1:.2f}.\n".format(name, round(donation_amount,2)) + return thank_you_message + + def delete_donation_neo(self, del_email): + """ + Ability to delete donors and their donations + """ + with self.driver.session() as session: + try: + cyph = """ + MATCH (d:Donor {email: '%s'}) + DELETE d + """ % (del_email) + print("{} has been removed from the database\n".format(del_email)) + except Exception as e: + print(f'Error deleting = {email}') + print(e) + + def donor_exists_neo(self, find_email): + """ + Determines if donor already exists in database + """ + with self.driver.session() as session: + current_donor = False + try: + cyph = "MATCH (d:Donor) RETURN d.email" + result = session.run(cyph) + for record in result: + if record == find_email: + current_donor = True + except Exception as e: + print(f'Error occurred. See below') + print(e) + return current_donor + + def write_to_file(self): + """ + Writes to a file. The donors name and total donations will be stored in the contents of the file, while the file name will be the donors email address + """ + with self.driver.session() as session: + try: + file_name = None + donor_file_name = None + full_file_name = None + complete_file_name = None + cyph = "MATCH (d:Donor) RETURN d.email" + result = session.run(cyph) + + for donor in result: + donor_file_name = donor['email'] + full_file_name = "{}.txt".format(donor_file_name) + complete_file_name = os.path.join(os.getcwd(), full_file_name) + letter = self.letter_to_file(donor_full_name,total_donations) + with open(complete_file_name, 'w+') as f: + f.write(letter) + + except Exception as e: + print("Error occurred. See below") + print(e) + print('\n') + + def letter_to_file(self, donor): + str_letter = "Dear {},\n\tThank you for your kind donation(s).\n\tIt will be put to very good use.\n\t\tSincerely,\n\t\t\t-The Team".format(donor) + return str_letter + + def show_donors(self): + """ + Lists the donor names + """ + with self.driver.session() as session: + str_build = "" + try: + cyph = """ + MATCH (d:Donor) + RETURN d.full_name as full_name, d.email as email + """ + result = session.run(cyph) + for record in result: + str_build += record['full_name'] + ' -- ' + record['email'] + '\n' + except Exception as e: + print("Error occurred. See below.") + print(e) + return str_build + + + + From 15e405711547c9a3a8b03ba90e3536969fdf2d17 Mon Sep 17 00:00:00 2001 From: Navdeep Gill Date: Sat, 9 Jun 2018 17:21:28 -0700 Subject: [PATCH 9/9] Menu for neo4j mailroom. Assignment 8 --- .../mailroom_database_menu_neo4j.py | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 students/navdeep/session18/mailroom_nosql/mailroom_database_menu_neo4j.py diff --git a/students/navdeep/session18/mailroom_nosql/mailroom_database_menu_neo4j.py b/students/navdeep/session18/mailroom_nosql/mailroom_database_menu_neo4j.py new file mode 100644 index 00000000..31e8f66b --- /dev/null +++ b/students/navdeep/session18/mailroom_nosql/mailroom_database_menu_neo4j.py @@ -0,0 +1,196 @@ +import os.path +from populate_mailroom_neo4j import ManipulateDBNeo + +def initializeOptionsDB(): + """ + Initializes the options the user can select from. A dictionary where the key is the option the user can select and the values are the functions that are called based off of the user's selection + :return: The options dictionary. + """ + options_dict = {'t': askUserForDonor, 's': writeToFile, 'r': createReport, 'd': delete_instance, 'e': exitMessage} + return options_dict + +def displayMenu(): + """ + displays the menu of options to the user + """ + str_menu = "\n1. Type 't' to add a name, donation and thank you card\n"+\ + "2. Type 'r' to Create a Report and see a list of the donors\n"+\ + "3. Type 's' to Send letters to everyone\n"+\ + "4. Type 'd' to delete a donor and their donations\n"+\ + "5. Type 'e' to exit the program\n" + #for testing purposes to determine menu is returned correctly + #return str_menu + print(str_menu) + +def menu(donor_collection_obj, menu_dict): + """ + This function will print out a menu of options for the user to choose from, + ask the user what action they would like to perform and then call the function that performs that action + :param donor_collection_obj: The database of donor objects + :param menu_dict: The dictionary of user options + """ + user_option = "" + while user_option.lower() != 'e': + displayMenu() + user_option = input("Select an option from the menu: ") + user_option = user_option.lower().strip() + #user_option = 't' #for testing purposes + #return user_option #used to test menu produces correct user input + try: + menu_dict[user_option](donor_collection_obj) + except KeyError as e: + print(e) + print("Invalid option selected. Please try again") + +def askUserForDonor(donor_collection_obj): + """ + Allows user to add a new donor object to the database or print out + the names of the current donors or exit back to the main menu. + The user can also type in the name of a donor that already + exists to append a new donation to that donor object + :param donor_collection_obj: the database of donor objects + """ + user_donor_option = "" + while user_donor_option != 'Exit': + user_donor_option = input("1. Type 'New' of a new donor\n" + "2. Type 'List' to list the donor names\n" + "3. Type 'Exit' to return to main menu\n" + "\nYour Selection: ") + + user_donor_option = clean_text(user_donor_option) + if user_donor_option == 'New': + addNewDonor(donor_collection_obj) + elif user_donor_option == 'List': + showDonorNames(donor_collection_obj) + elif user_donor_option == 'Exit': + return + else: + print("Please select a valid option:") + print() + +def addNewDonor(donor_collection_obj): + """ + Prompts the user for a first name, last name, email for the donor object, regardless of whether or not the donor currently exists. The user cannot enter in a blank string as a name. + :param donor_collection_obj: The database of donor objects + """ + first_name = None + last_name = None + email = None + invalid = True + while invalid == True: + try: + first_name = input("Enter first name for donor: ") + last_name = input("Enter last name for donor: ") + email = input("Enter email for donor: ") + if first_name == "" or last_name == "" or email == "": + raise ValueError + except ValueError as e: + print("The name you entered is invalid. Enter proper first/last name") + else: + first_name, last_name = clean_text(first_name), clean_text(last_name) + email = email.strip() + invalid = False + addNewDonation(donor_collection_obj, first_name, last_name, email) + +def addNewDonation(donor_collection_obj, first_name, last_name, email): + """ + Allows the user to input a new donation for the user. The user must + enter a valid amount (integer or float). The user must + also enter a value greater than 0. If the donor currently exists + in the dictionary, the donor's new donation will be appended to the list stored under their name, which is the key in the dictionary. If the donor does not exist in the database, a new donor object will be created + :param donor_collection_obj: the database of donor objects + :param first_name: first name of the new donor, a string + :param last_name: last name of the new donor + """ + new_donation = getUserValue("Donation Amount") + donor_collection_obj.add_donor_neo(first_name, last_name, email, new_donation) + print(donor_collection_obj.thank_you_message(first_name, new_donation)) + +def getUserValue(str_reason = "value"): + """ + This function will ask the user for a numeric value. This function is used when the user is entering in a new donation amount, entering a factor they would like to multiply the current donations by or setting the boundary for the specific donations they want to factor. + :param str_reason: The reason why the user is being asked to enter in a number. For example, str_reason will equal "donation" when the user is supposed to enter in a new donation amount. + :return: Returns the value the user entered + """ + invalid = True + while invalid == True: + try: + user_value = float(input("Enter number for {}: ".format(str_reason))) + if type(user_value) != float or user_value < 1: + raise ValueError + except ValueError: + print("\nThe value you entered was illegal\n") + else: + invalid = False + return user_value + +def clean_text(name): + """ + Eliminates text of whitespace, lowercase all letters and capitalize the first letter + """ + name = name.strip() + name = name.lower() + name = name.title() + return name + +def delete_instance(donor_collection_obj): + invalid = True + while invalid == True: + try: + del_email = input("Enter email of donor you would like to delete: ") + if del_email == "" or not donor_collection_obj.donor_exists_neo(del_email): + raise ValueError + except ValueError: + print("\nEmail does not exist in database.\n") + else: + invalid = False + donor_collection_obj.delete_donation_neo(del_email) + + +def showDonorNames(donor_collection_obj): + """ + Prints out the full names of each donor + :param donor_collection_obj: The database of donors + """ + print() + print(donor_collection_obj.show_donors()) + + +def writeToFile(donor_collection_obj): + """ + Allows user to save a letter written to each donor and their donation amounts to the current working directory + :param donor_collection_obj: The database of donor objects + """ + donor_collection_obj.write_to_file() + +def createReport(donor_collection_obj): + """ + Allows user to create a report that shows each donor's name, total donated, number of times donated and average donations. This function calls the donor collection objects create report method, which generates the report. + :param donor_collection_obj: The database of donor objects + """ + report_header() + print(donor_collection_obj.create_report()) + +def report_header(): + str_header = ('\n{:25s} | {:25s} | {:11s} | {:9s} | {:12s}'.format("Donor Name", "Donor Email", "Total Given", "Num Gifts", "Average Gift")) + str_header = str_header + '\n' + ("-"*95) + print(str_header) + +def exitMessage(donor_collection_obj): + """ + Exit message once the user decides to end the entire program + All of the donors stored in the donor_collection object will be printed + a final time + :param donor_collection_obj:The database of donor objects + """ + print("\nThank you to the following donors for all of your donations: \n") + showDonorNames(donor_collection_obj) + print("\nCome back anytime to donate more!") + + +user = input("Username: ") +password = input("Password: ") +url = input("URL: ") +store_donors = ManipulateDBNeo(user, password, url) +menu_dict = initializeOptionsDB() +menu(store_donors, menu_dict)