diff --git a/zygrader/class_manager.py b/zygrader/class_manager.py index a1787e0..f21e7d6 100644 --- a/zygrader/class_manager.py +++ b/zygrader/class_manager.py @@ -8,6 +8,7 @@ from zygrader.zybooks import Zybooks from zygrader import data from zygrader.config.shared import SharedData +from zygrader.utils import ZybookSectionSelector def save_roster(roster): """Save the roster of students to a json file""" @@ -71,30 +72,23 @@ def add_lab(): # Get lab part(s) parts = [] - number = window.create_text_input("Enter Part", "Enter Chapter.section, e.g. 2.26 (ESC to cancel)") - while number != Window.CANCEL: - part = {} - chapter, section = number.split(".") + section_selector = ZybookSectionSelector() + section_numbers = section_selector.select_zybook_sections(return_just_numbers=True) + for chapter, section in section_numbers: + part = {} response = zy_api.get_zybook_section(chapter, section) if not response.success: window.create_popup("Error", ["Invalid URL"]) - else: - # Name lab part and add to list of parts - name = window.create_text_input("Part Name", "Enter new part name") - if name == Window.CANCEL: - name = response.name - - part["name"] = name - part["id"] = response.id - parts.append(part) - - # Get next part - number = window.create_text_input("Enter Part", "Enter Chapter.section, e.g. 2.26 (ESC to finish)") + part["name"] = response.name + part["id"] = response.id + parts.append(part) new_lab = data.model.Lab(lab_name, parts, {}) + edit_lab_options(new_lab) + all_labs = data.get_labs() all_labs.append(new_lab) diff --git a/zygrader/grade_puller.py b/zygrader/grade_puller.py index d1f2936..28b8cb6 100644 --- a/zygrader/grade_puller.py +++ b/zygrader/grade_puller.py @@ -5,6 +5,7 @@ from zygrader.ui import UI_GO_BACK from zygrader.config.shared import SharedData from zygrader.zybooks import Zybooks +from zygrader.utils import ZybookSectionSelector, fetch_zybooks_toc def create_last_night(): now = datetime.datetime.now() @@ -27,7 +28,6 @@ def __init__(self): def pull(self): try: self.read_canvas_csv() - self.fetch_zybooks_toc() self.selected_assignments = [] more_assignments = True @@ -65,14 +65,6 @@ def read_canvas_csv(self): self.window.create_popup("Error in Reading Master CSV", [f"Could not open {path} for reading", "Please have the owner of the file grant read permissions"]) raise GradePuller.StoppingException() - def fetch_zybooks_toc(self): - wait_controller = self.window.create_waiting_popup("TOC", ["Fetching TOC from zyBooks"]) - toc = self.zy_api.get_table_of_contents() - wait_controller.close() - if not toc: - raise GradePuller.StoppingException() - self.zybooks_toc = toc - def select_canvas_assignment(self): real_assignments = self.canvas_header[GradePuller.NUM_CANVAS_ID_COLUMNS:] index = self.window.create_filtered_list("Assignment", input_data=real_assignments) @@ -81,55 +73,11 @@ def select_canvas_assignment(self): return real_assignments[index] def select_zybook_sections(self): - class ZybookSectionSelector: - def __init__(self, grade_puller): - self.outer = grade_puller - self.zybooks_sections = {(chapter['number'], section['number']): section for chapter in self.outer.zybooks_toc for section in chapter['sections']} - - def draw_zybook_sections(self, chapters_expanded, selected_sections): - res = [] - items = [] - for chapter in self.outer.zybooks_toc: - res.append(f"{chapter['number']} - {chapter['title']}") - items.append(chapter['number']) - if chapters_expanded[chapter['number']]: - for section in chapter['sections']: - section_string = f"{chapter['number']}.{section['number']} - {section['title']}" - is_selected = selected_sections[(chapter['number'], section['number'])] - if not section['hidden'] and not section['optional']: - res.append(f" [{'X' if is_selected else ' '}] {section_string}") - else: - res.append(f" -{'X' if is_selected else '-'}- {section_string} (hidden/optional)") - items.append((chapter['number'], section['number'])) - self.drawn_zybook_items = items - return res - - def select_zybook_sections_callback(self, chapters_expanded, selected_sections, selected_index): - item = self.drawn_zybook_items[selected_index] - if isinstance(item, tuple): #is a section - section = self.zybooks_sections[item] - if not section['hidden'] and not section['optional']: - selected_sections[item] = not selected_sections[item] - else: #is a chapter - chapters_expanded[item] = not chapters_expanded[item] - - def select_zybook_sections(self): - chapters_expanded = {chapter['number']: False for chapter in self.outer.zybooks_toc} - selected_sections = {(chapter['number'], section['number']): False for chapter in self.outer.zybooks_toc for section in chapter['sections']} - draw_sections = lambda: self.draw_zybook_sections(chapters_expanded, selected_sections) - draw_sections() - section_callback = lambda context: self.select_zybook_sections_callback(chapters_expanded, selected_sections, context.data) - self.outer.window.create_list_popup("Select zyBook Sections (use Back to finish)", callback=section_callback, list_fill=draw_sections) - res = [] - for section_numbers, selected in selected_sections.items(): - if selected: - res.append(self.zybooks_sections[section_numbers]) - if not res: - raise GradePuller.StoppingException() - return res - - selector = ZybookSectionSelector(self) - return selector.select_zybook_sections() + selector = ZybookSectionSelector() + res = selector.select_zybook_sections() + if not res: + raise GradePuller.StoppingException() + return res def select_class_sections(self): num_sections = len(self.canvas_students[-1]['Section'].split('and')) #Test Student has id -1, and is in every section @@ -252,9 +200,9 @@ def write_upload_file(self, selected_canvas_assignment): def find_unmatched_students(self): try: self.read_canvas_csv() - self.fetch_zybooks_toc() + zybooks_toc = fetch_zybooks_toc() - zybook_section_1_1 = self.zybooks_toc[0]['sections'][0] + zybook_section_1_1 = zybooks_toc[0]['sections'][0] wait_msg = ["Fetching a completion report from zyBooks"] wait_controller = self.window.create_waiting_popup("Fetch Reports", wait_msg) zybooks_students, zybooks_header = self.fetch_completion_report(create_last_night(), [zybook_section_1_1]) diff --git a/zygrader/utils.py b/zygrader/utils.py index 998e9a8..2ebe783 100644 --- a/zygrader/utils.py +++ b/zygrader/utils.py @@ -14,6 +14,8 @@ from zygrader import data from zygrader import ui from zygrader.ui import components +from zygrader.zybooks import Zybooks +from zygrader.ui.window import Window def suspend_curses(callback_fn): @@ -161,3 +163,63 @@ def view_students(): window.create_filtered_list("Student Name", input_data=students, callback=view_students_callback) + +def fetch_zybooks_toc(): + wait_controller = Window.get_window().create_waiting_popup("TOC", ["Fetching TOC from zyBooks"]) + zy_api = Zybooks() + toc = zy_api.get_table_of_contents() + wait_controller.close() + return toc + +class ZybookSectionSelector: + def __init__(self): + self.window = Window.get_window() + self.zy_api = Zybooks() + + def draw_zybook_sections(self, chapters_expanded, selected_sections): + res = [] + items = [] + for chapter in self.zybooks_toc: + res.append(f"{chapter['number']} - {chapter['title']}") + items.append(chapter['number']) + if chapters_expanded[chapter['number']]: + for section in chapter['sections']: + section_string = f"{chapter['number']}.{section['number']} - {section['title']}" + is_selected = selected_sections[(chapter['number'], section['number'])] + if not section['hidden'] and not section['optional']: + res.append(f" [{'X' if is_selected else ' '}] {section_string}") + else: + res.append(f" -{'X' if is_selected else '-'}- {section_string} (hidden/optional)") + items.append((chapter['number'], section['number'])) + self.drawn_zybook_items = items + return res + + def select_zybook_sections_callback(self, chapters_expanded, selected_sections, selected_index): + item = self.drawn_zybook_items[selected_index] + if isinstance(item, tuple): #is a section + section = self.zybooks_sections[item] + if not section['hidden'] and not section['optional']: + selected_sections[item] = not selected_sections[item] + else: #is a chapter + chapters_expanded[item] = not chapters_expanded[item] + + def select_zybook_sections(self, return_just_numbers=False): + self.zybooks_toc = self.zy_api.get_table_of_contents() + if not self.zybooks_toc: + return None + self.zybooks_sections = {(chapter['number'], section['number']): section for chapter in self.zybooks_toc for section in chapter['sections']} + + chapters_expanded = {chapter['number']: False for chapter in self.zybooks_toc} + selected_sections = {(chapter['number'], section['number']): False for chapter in self.zybooks_toc for section in chapter['sections']} + draw_sections = lambda: self.draw_zybook_sections(chapters_expanded, selected_sections) + draw_sections() + section_callback = lambda context: self.select_zybook_sections_callback(chapters_expanded, selected_sections, context.data) + self.window.create_list_popup("Select zyBook Sections (use Back to finish)", callback=section_callback, list_fill=draw_sections) + res = [] + for section_numbers, selected in selected_sections.items(): + if selected: + if return_just_numbers: + res.append(section_numbers) + else: + res.append(self.zybooks_sections[section_numbers]) + return res \ No newline at end of file