class Entry(dict): '''The worklog entry class contains all properties and methods CRUD operations, pertaining to log entries.''' def __init__(self): super().__init__() self.utils = Utilities() self.validation = Validation() def _display_keep_current_value(self, value): '''Small internal helper method for display a message when no results are found during a search of the log.''' self.utils.clear_screen() print('Press enter to keep current value: {}'.format(value)) print('-----------------') def _get_entry_data(self, editing=False, log_to_edit=None): '''This is an internal method of the Entry class The purpose of this method is to house the logic for asking a user for input regarding the creation or updating of a record in the log.''' if not editing: self['id'] = ''.join( random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890') for _ in range(20)) else: self['id'] = log_to_edit['id'] current_title = " ({})".format(log_to_edit['title']) if editing else '' current_date = " ({})".format(log_to_edit['date']) if editing else '' current_time_spent = " ({})".format( log_to_edit['time_spent']) if editing else '' current_notes = " ({})".format(log_to_edit['notes']) if editing else '' self['title'] = input("\nPlease choose a title for this entry{}: ". format(current_title)) or log_to_edit['title'] while True: self['date'] = (input("\nPlease enter a date (ex. MM/DD/YYYY){}: ". format(current_date)) or log_to_edit['date']) if not self.validation.is_valid_date(self['date']): self.utils.clear_screen() continue break while True: self['time_spent'] = (input( "\nPlease enter the time spent on this entry in hours{}: ". format(current_time_spent)) or log_to_edit['time_spent']) if not self.validation.is_valid_number(self['time_spent']): self.utils.clear_screen() continue break self['notes'] = (input( "\nEnter any notes about this entry (optional){}: ".format( current_notes)) or log_to_edit['notes']) def create_new_entry(self): '''Method to create a new work entry. This method walks the user through a series of questions allowing them to create a single entry consisting of a date entered, a title, the time spent working and some optional notes if desired''' self._get_entry_data() with open(constants.FILENAME, 'a') as file: writer = csv.DictWriter(file, fieldnames=constants.FIELDNAMES) writer.writerow(self) self.utils.clear_screen() input("\nEntry has been added, " "press enter to return to the main menu") def update_current_entry(self, entry_id, edit_mode): '''Method for updating records of the worklog. This method takes the id of the entry to update and the type of update to make via the edit_mode argument.''' worklog = self.utils.read_file() status = 'updated' if edit_mode == 'edit' else 'deleted' for index, entry in enumerate(worklog): if entry['id'] == entry_id: if edit_mode == 'edit': self._get_entry_data(editing=True, log_to_edit=entry) worklog[index] = self if edit_mode == 'delete': del worklog[index] with open('worklog.csv', 'w') as log: writer = csv.DictWriter(log, constants.FIELDNAMES) writer.writeheader() for row in worklog: writer.writerow(row) self.utils.clear_screen() input("\nEntry has been {}! Press enter to continue.".format(status))
class Search: '''This class contains all methods for searching the worklog and displaying the results''' def __init__(self): self.utils = Utilities() self.validation = Validation() self.entry = Entry() self.menu = Menu() self.results = list() def search(self, query_text, search_type=''): '''Method for searching the worklog This method takes the text to ask the user for input and the type of search to conduct.''' while True: self.utils.clear_screen() query = input(query_text).lower() worklog = self.utils.read_file() if search_type == 'date': if not self.validation.is_valid_date(query): continue elif search_type == 'time_spent': if not self.validation.is_valid_number(query): continue elif search_type == 'exact_match' or search_type == 'regex': if not self.validation.is_valid_input(query): continue elif search_type == 'date_range': if not self.validation.is_valid_date_range(query.split(', ')): continue search = re.compile(r'{}'.format(query), re.I) for line in worklog: if search_type == 'date' or search_type == 'time_spent': if search.match(line[search_type]): self.results.append(line) elif search_type == 'exact_match' or search_type == 'regex': if search.findall(line['title']) \ or search.findall(line['notes']): self.results.append(line) elif search_type == 'date_range': real_date = datetime.strptime(line['date'], '%m/%d/%Y') date_range = query.split(', ') if (datetime.strptime(date_range[0], '%m/%d/%Y') <= real_date and datetime.strptime( date_range[1], '%m/%d/%Y') >= real_date): self.results.append(line) if not self.results: print("-------------------------------\n") print('No results found...') input('Press Enter to try again.') continue else: self.display_search_results() break def display_search_results(self): '''This method displays the results of a user search if any are found.''' index = 0 while True: num_results = len(self.results) entry = self.results[index] self.utils.clear_screen() print('\n{} Search Results Found'.format(num_results)) print("-------------------------------\n") print('title: {}'.format(entry['title'])) print('date: {}'.format(entry['date'])) print('time spent: {}'.format(entry['time_spent'])) print('notes: {}'.format(entry['notes'])) print("-------------------------------") print('Result {}/{}'.format((index + 1), num_results)) print("-------------------------------\n") choice = input("Choose an action: " "[N]ext, " "[P]revious, " "[E]dit, " "[D]elete, " "[S]earch Menu: ").lower() if not self.validation.is_valid_input(choice, menu='npeds'): self.utils.clear_screen() continue if choice == 'n': if index != (len(self.results) - 1): index += 1 else: index = 0 elif choice == 'p': if index != 0: index -= 1 else: index = (len(self.results) - 1) elif choice == 'e' or choice == 's' or choice == 'd': if choice == 'e': self.entry.update_current_entry(entry['id'], edit_mode='edit') if choice == 'd': self.entry.update_current_entry(entry['id'], edit_mode='delete') self.menu.display(constants.SEARCH_MENU) self.results = list() break
def access_log(self): '''Method containing the main loop to run the program.''' menu = Menu() entry = Entry() utils = Utilities() search = Search() validation = Validation() current_menu = constants.MAIN_MENU if not os.path.exists(constants.FILENAME): with open(constants.FILENAME, 'a') as file: writer = csv.DictWriter(file, fieldnames=constants.FIELDNAMES) writer.writeheader() while True: utils.clear_screen() menu.display(current_menu) choice = menu.get_user_choice() if current_menu == constants.MAIN_MENU: if not validation.is_valid_input(choice, menu='csq'): continue if choice == 'c': utils.clear_screen() entry.create_new_entry() elif choice == 's': current_menu = constants.SEARCH_MENU elif choice == 'q': break elif current_menu == constants.SEARCH_MENU: if not validation.is_valid_input(choice, menu='edtprm'): continue if choice == 'e': search.search('Please enter a date to search: ', 'date') elif choice == 'd': search.search( 'Please enter two comma separated dates to search' '\n(ex. 01/15/1982, 12/11/2017): ', 'date_range') elif choice == 't': search.search( 'Please enter a time to search: ', 'time_spent') elif choice == 'p': search.search( 'Please enter a word or phrase to search: ', 'exact_match') elif choice == 'r': search.search( 'Please enter a word or phrase to search: ', 'regex') elif choice == 'm': current_menu = constants.MAIN_MENU