def validate_meeting_general(meeting: Dict) -> ResultWithData[MeetingJsonData]: date_res = validate_date(meeting, "date") if date_res.is_error: return get_result_with_error(date_res.message) date = date_res.data last_upload_res = validate_date(meeting, "last_upload_date") if last_upload_res.is_error: return get_result_with_error(last_upload_res.message) last_upload = last_upload_res.data lp_res = validate_int(meeting, "lp") if lp_res.is_error: return get_result_with_error(lp_res.message) lp = lp_res.data meeting_no_res = validate_int(meeting, "meeting_no") if meeting_no_res.is_error: return get_result_with_error(meeting_no_res.message) meeting_no = meeting_no_res.data if not 0 < lp <= 4: return get_result_with_error("Invalid lp {0}".format(lp)) if not 0 <= meeting_no: return get_result_with_error( "Invalid meeting number {0}".format(meeting_no)) return get_result_with_data( MeetingJsonData(id=None, date=date, last_upload=last_upload, lp=lp, meeting_no=meeting_no, groups_tasks=[]))
def validate_configs(data: Dict) -> ResultWithData[List[ConfigData]]: configs = [] if "config" not in data: return get_result_with_error("Missing config array") config = data["config"] for entry in config: if "key" not in entry or "value" not in entry: return get_result_with_error("Missing key or value") key = entry["key"] value = entry["value"] db_config = get_config(key) if db_config is None: return get_result_with_error("Config {0} not found".format(key)) if db_config.config_type == "number": if not value.isdigit(): return get_result_with_error( "Config {0} must be a number, got {1}".format(key, value)) configs.append(ConfigData(key=key, value=value)) return get_result_with_data(configs)
def update_groups_tasks( meeting_id: uuid, groups_tasks: List[GroupTaskData]) -> ResultWithData[str]: # Remove group_tasks existing_group_tasks = get_tasks_for_meeting(meeting_id) for existing_group_task in existing_group_tasks: found = False for group_task in groups_tasks: if group_task.is_same(existing_group_task): found = True break if not found: # Remove the group_task res = remove_group_meeting_task(meeting_id, existing_group_task.group_name, "active", existing_group_task.task_type) if res.is_error: return get_result_with_error(res.message) # Add new group_tasks for group_task in groups_tasks: create_group_meeting(meeting_id, group_task.group_name, "active") create_group_meeting_task(meeting_id, group_task.group_name, "active", group_task.task_type) return get_result_with_data("")
def validate_stories( config: Dict[str, object]) -> ResultWithData[List[StoryData]]: story_groups_res = validate_list(config, "storyGroups") if story_groups_res.is_error: return get_result_with_error(story_groups_res.message) story_groups = story_groups_res.data story_groups_list = [] for sg in story_groups: group_res = validate_str(sg, "group") if group_res.is_error: return get_result_with_error(group_res.message) group = group_res.data year_res = validate_int(sg, "year") if year_res.is_error: return get_result_with_error(year_res.message) year = year_res.data finished_res = validate_bool(sg, "finished") if finished_res.is_error: return get_result_with_error(finished_res.message) finished = finished_res.data story_groups_list.append(StoryData(group, str(year), finished)) return get_result_with_data(story_groups_list)
def create_archive(id: UUID) -> ResultWithData[UUID]: folder_location = "src/b" meeting = get_meeting_data_by_id(id) if os.path.exists(folder_location): # Delete any old files. shutil.rmtree(folder_location) os.makedirs(folder_location) file_paths = get_file_paths(id) for path in file_paths: shutil.copy(path, folder_location) archives_location = "archives" folder_name = f"src/{archives_location}" if not os.path.exists(folder_name): os.makedirs(folder_name) archive_name = f"{archives_location}/documents_lp{meeting.lp}_{meeting.meeting_no}_{meeting.year}" print(f"Archiving folder: {folder_location}\nTo file: {archive_name}") shutil.make_archive(f"src/{archive_name}", "zip", folder_location) old_archive = get_archive_data_by_meeting_id(meeting.id) if old_archive is None: # Create a new archive. new_archive = create_archive_code(meeting.id, archive_name) else: # Update the archive for this meeting with the new zip file. new_archive = update_archive_location(old_archive.code, archive_name) if new_archive is None: return get_result_with_error("Failed creating/updating archive") return get_result_with_data(new_archive.code)
def validate_dict(json: Dict, key: str) -> ResultWithData[Dict]: if key not in json: return get_result_with_error("Missing {0}".format(key)) value = json[key] if type(value) is not dict: return get_result_with_error("{0} must be an object".format(key)) return get_result_with_data(value)
def get_meeting_json_data(code: UUID) -> ResultWithData[MeetingJsonData]: meeting = get_meeting_by_id(code) if meeting is None: return get_result_with_error("No meeting with code {0}".format(code)) groups_tasks = get_tasks_for_meeting(code) return get_result_with_data( MeetingJsonData(meeting.id, meeting.date, meeting.last_upload, meeting.lp, meeting.meeting_no, groups_tasks))
def validate_bool(json: Dict, key: str) -> ResultWithData[bool]: if key not in json: return get_result_with_error("Missing {0}".format(key)) bool_str = json[key] try: val = bool(bool_str) return get_result_with_data(val) except ValueError: get_result_with_error("{0} is not a valid boolean".format(bool_str))
def get_years() -> ResultWithData[dict]: years = [] curr_year = datetime.utcnow().year years_back_res = get_config_value_int("possible_years_back_for_stories") if years_back_res.is_error: return get_result_with_error(years_back_res.message) for i in range(years_back_res.data): years.append(curr_year - i) return get_result_with_data(years)
def get_meetings(meeting_ids: List[UUID]) -> ResultWithData[List[dict]]: meetings = [] for meeting_id in meeting_ids: meeting_data_res = get_meeting_json_data(meeting_id) if meeting_data_res.is_error: return get_result_with_error(meeting_data_res.message) meetings.append(meeting_data_res.data.to_json()) return get_result_with_data(meetings)
def send_board_email(meeting: MeetingData) -> ResultWithData: archive_id_res = create_archive(meeting.id) if archive_id_res.is_error: return get_result_with_error(archive_id_res.message) archive = get_archive_data_by_code(archive_id_res.data) print(f"Archive should now be available at '{archive.get_archive_location()}'") mail_data = get_board_email_data(meeting, archive) send_email(mail_data) return get_result_with_data("")
def handle_file(code: uuid, task: str, file) -> ResultWithData[bool]: """ Saves the file to the disk and stores it's location in the database """ task_obj = get_task_by_name(task) if task_obj is None: return get_result_with_error("Report type not found {0}".format(task)) save_location = save_file(code, task, file) group_file = get_group_meeting_file_from_code(code, task) if group_file is None: create_group_meeting_file(code, task, save_location) return get_result_with_data(False) print("Overwriting file {0} from {1} (GMT)".format( group_file.file_location, group_file.date)) new_date = datetime.utcnow() update_upload_date_for_file(code, task, new_date) return get_result_with_data(True)
def remove_group_meeting_task(meeting_id: UUID, group_name: str, year: str, task_name: str) -> ResultWithData[str]: group_meeting_task = get_group_meeting_task(meeting_id, group_name, year, task_name) if group_meeting_task is None: return get_result_with_data( "No group_meeting_task was found for meeting_id: {0}, group: {1}, year: {2}, task_name: {3}" .format(meeting_id, group_name, year, task_name)) try: group_meeting_task.delete() return get_result_with_data("") except ConstraintError: if year == "active": year_txt = "" else: year_txt = str(year) return get_result_with_error( f"Cannot remove task {task_name} for group {group_name}{year_txt} as there is files already uploaded for it." )
def update_meeting(meeting_data: MeetingJsonData) -> ResultWithData[str]: try: meeting = Meeting.get(id=meeting_data.id) meeting.date = meeting_data.date meeting.last_upload = meeting_data.last_upload meeting.lp = meeting_data.lp meeting.meeting_no = meeting_data.meeting_no except Exception as e: return get_result_with_error("Failed to update meeting {0}".format(e)) return get_result_with_data("")
def validate_meeting_id_from_str(id: str) -> ResultWithData[UUID]: code_res = validate_code(id) if code_res.is_error: return get_result_with_error(code_res.message) code = code_res.data meeting = get_meeting_by_id(code) if meeting is None: return get_result_with_error("No meeting exists with id {0}") return get_result_with_data(meeting.id)
def validate_int(json: Dict, key: str) -> ResultWithData[int]: if key not in json: return get_result_with_error("Missing {0}".format(key)) int_str = json[key] try: val = int(int_str) return get_result_with_data(val) except ValueError: return get_result_with_error( "{0} is not a valid integer".format(int_str))
def create_new_meeting(date: datetime, last_upload: datetime, lp: int, meeting_no: int) -> ResultWithData[UUID]: try: meeting = Meeting(year=date.year, date=date, last_upload=last_upload, lp=lp, meeting_no=meeting_no, check_for_deadline=False) except Exception as e: print("Failed to create meeting due to '{0}'".format(e)) return get_result_with_error("Failed to create meeting") return get_result_with_data(meeting.id)
def validate_date(json: Dict, key: str) -> ResultWithData[datetime]: if key not in json: return get_result_with_error("Missing {0}".format(key)) date_str = json[key] try: date = parse(date_str) return get_result_with_data(date) except ValueError: return get_result_with_error( "{0} is not a valid date".format(date_str)) except OverflowError: return get_result_with_error("{0} is too large ".format(date_str))
def update_stories(story_groups: List[StoryData]) -> ResultWithData[str]: for story_group in story_groups: group_year = get_group_year(story_group.group, story_group.year) if group_year is None: create_res = create_group_year(story_group.group, story_group.year, story_group.finished) if create_res is None: return get_result_with_error( "Failed to create group year for {0} {1} {2}".format( story_group.group, story_group.year, story_group.finished)) else: update_group_year(story_group.group, story_group.year, story_group.finished) return get_result_with_data("")
def get_data_for_code(code: uuid) -> ResultWithData[Dict]: group_meeting = get_group_meeting_by_code(code) if group_meeting is None: return get_result_with_error("Unable to find meeting for code {0}".format(str(code))) tasks = get_tasks_dict_for_code(code) meeting = get_meeting_data_from_code(code) group_year = get_group_year_data_from_code(code) return get_result_with_data({ "group": group_year.to_json(), "study_period": meeting.lp, "year": meeting.year, "meeting_no": meeting.meeting_no, "tasks": tasks })
def validate_meeting(data: Dict) -> ResultWithData[MeetingJsonData]: meeting_res = validate_dict(data, "meeting") if meeting_res.is_error: return get_result_with_error(meeting_res.message) meeting = meeting_res.data if "id" not in meeting: return get_result_with_error("Missing id") id_str = meeting["id"] general_res = validate_meeting_general(meeting) if general_res.is_error: return get_result_with_error(general_res.message) meeting_data = general_res.data if id_str == "new": same_period_meeting = get_meeting_for_period(meeting_data.date.year, meeting_data.lp, meeting_data.meeting_no) if same_period_meeting is not None: return get_result_with_error( "A meeting already exists for {0}-lp{1}-{2}".format( meeting_data.date.year, meeting_data.lp, meeting_data.meeting_no)) else: code_res = validate_code(id_str) if code_res.is_error: return get_result_with_error( "Invalid meeting id {0}".format(id_str)) code = code_res.data # Validate that the meeting exists meeting_res = get_meeting_by_id(code) if meeting_res is None: return get_result_with_error("No meeting with id {0}".format(code)) meeting_data.id = meeting_res.id groups_tasks_res = validate_groups_tasks(meeting) if groups_tasks_res.is_error: return get_result_with_error(groups_tasks_res.message) meeting_data.groups_tasks = groups_tasks_res.data return get_result_with_data(meeting_data)
def update_meeting_data(meeting_data: MeetingJsonData) -> ResultWithData[str]: if meeting_data.id is None: # The meeting does not yet exist, create it. create_meeting_res = create_new_meeting( date=meeting_data.date, last_upload=meeting_data.last_upload, lp=meeting_data.lp, meeting_no=meeting_data.meeting_no) if create_meeting_res.is_error: return get_result_with_error(create_meeting_res.message) meeting_data.id = create_meeting_res.data else: update_res = update_meeting(meeting_data) if update_res.is_error: return get_result_with_error(update_res.message) gt_res = update_groups_tasks(meeting_data.id, meeting_data.groups_tasks) if gt_res.is_error: return get_result_with_error(gt_res.message) return get_result_with_data("")
def validate_groups_tasks( meeting: Dict) -> ResultWithData[List[GroupTaskData]]: groups_tasks_res = validate_dict(meeting, "groups_tasks") if groups_tasks_res.is_error: return get_result_with_error(groups_tasks_res.message) groups_tasks = groups_tasks_res.data group_task_datas = [] for task_type in groups_tasks: task = get_task_by_name(task_type) if task is None: return get_result_with_error("Invalid task {0}".format(task_type)) task_groups_res = validate_list(groups_tasks, task_type) if task_groups_res.is_error: return get_result_with_error(task_groups_res.message) task_groups = task_groups_res.data for group_task in task_groups: name_res = validate_str(group_task, "name") if name_res.is_error: return get_result_with_error(name_res.message) name = name_res.data group = get_group_by_name(name) if group is None: return get_result_with_error("No such group {0}".format(name)) group_task_datas.append( GroupTaskData(code=None, group_name=group.name, task_type=task.name)) return get_result_with_data(group_task_datas)
def validate_code(code: str) -> ResultWithData[UUID]: try: return get_result_with_data(UUID(code)) except ValueError: return get_result_with_error("Invalid code format")
def get_config_value_int(config_key: str) -> ResultWithData[int]: value = get_config_value(config_key) try: return get_result_with_data(int(value)) except ValueError: return get_result_with_error(f"Config value {value} for key {config_key} is not a valid integer")
def validate_str(json: Dict, key: str) -> ResultWithData[str]: if key not in json: return get_result_with_error("Missing {0}".format(key)) return get_result_with_data(json[key])