def school_name(self, principal_email: str): if not isinstance(principal_email, str): raise InvalidTypeException( f"The principal's email provided is not a str (type provided is {type(principal_email)})." ) if not re.match(r"^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$", principal_email): raise InvalidTypeException( "The principal's email provided is not a valid email.") self._principal_email = principal_email
def school_address(self, school_address: str): if not isinstance(school_address, str): raise InvalidTypeException( f"The school address provided is not a str (type provided is {type(school_address)})." ) self._school_address = school_address
def department_description(self, department_description: list): if not isinstance(department_description, list): raise InvalidTypeException( f"The department descriptions provided are not a list (type provided is {type(department_description)})." ) self._department_description = department_description
def departments(self, departments: list): if not isinstance(departments, list): raise InvalidTypeException( f"The departments provided are not a list (type provided is {type(departments)})." ) self._departments = departments
def grading(self, grading: list): if not isinstance(grading, list): raise InvalidTypeException( f"The grading provided is not a list (type provided is {type(grading)})." ) self._grading = grading
def grade_weights(self, grade_weights: bool): if not isinstance(self, grade_weights, bool): raise InvalidTypeException( f"The grade weights provided is not a boolean (type provided is {type(department_description)})." ) self._grade_weights = grade_weights
def teacher(self, teacher_id: Union[str, ObjectId]): from api.classes import Teacher if isinstance(teacher_id, ObjectId): teacher_id = str(teacher_id) if not isinstance(teacher_id, str): raise InvalidTypeException( f"The teacher_id provided is not a str (type provided is {type(teacher_id)})." ) if teacher_id == "": self._teacher = teacher_id return try: ObjectId(teacher_id) except Exception as e: logger.exception(f"Error while validating teacher id {teacher_id}") raise e try: if Teacher.get_by_id(teacher_id) is None: raise Exception( f"The teacher with id {teacher_id} does not exist.") except Exception as e: logger.exception( f"Error while validating the existence of teacher {teacher_id}" ) raise e self._teacher = teacher_id
def department(self, department: str): if not isinstance(department, str): raise InvalidTypeException( f"The department provided is not a string (type provided is {type(department)})." ) self._department = department
def bio(self, bio: str): if not isinstance(bio, str): raise InvalidTypeException( f"The bio provided is not a str (type provided is {type(bio)})." ) if bio == "": self._bio = "A short bio." return if not 0 < len(bio) <= 100: raise InvalidFormatException( f"The string provided is too long. The bio should not exceed 100 characters. (currently: {len(bio)})" ) if not re.match( r'[\w \.\+\(\)\[\]\{\}\?\*\&\^\%\$\#\/\'"~<>,:;!-_=@]{1,100}', bio, flags=re.UNICODE, ): raise InvalidFormatException( r"The format for bio doesn't match. Expected '[\w \.\+\(\)\[\]\{\}\?\*\&\^\%\$\#\/\'\"~<>,:;!-_=@]{1, 500}', got {bio}" .format(bio=bio)) self._bio = bio
def activated(self, activated: bool): if not isinstance(activated, bool): raise InvalidTypeException( f"The activated provided is not a bool (type provided is {type(activated)})" ) self._activated = activated
def school_name(self, phone_number: str): if not isinstance(phone_number, str): raise InvalidTypeException( f"The phone number provided is not a str (type provided is {type(phone_number)})." ) self._phone_number = phone_number
def schedule_time(self, schedule_time: str): if not isinstance(schedule_time, str): raise InvalidTypeException( f"The schedule_time provided is not a str (type provided is {type(schedule_time)}" ) if schedule_time == "": self._schedule_time = "" return if not re.match( r"([0-1][0-9]|2[0-4]):[0-5][0-9]-([0-1][0-9]|2[0-4]):[0-5][0-9]", schedule_time, ): raise InvalidFormatException( f"The format for schedule_time doesn't match. Expected '([0-1][0-9] | 2[0-4]):[0-5][0-9]-([0-1][0-9] | 2[0-4]):[0-5][0-9]', got {schedule_time}" ) start_time, finish_time = schedule_time.split("-") start_time_h, start_time_m = list(map(int, start_time.split(":"))) finish_time_h, finish_time_m = list(map(int, finish_time.split(":"))) if (start_time_h * 60 + start_time_m >= finish_time_h * 60 + finish_time_m) and not (start_time_h == 23 and finish_time_h == 0): raise InvalidFormatException( f"The start time for schedule_time must be earlier than the finish time (got {schedule_time})" ) self._schedule_time = schedule_time
def profile_picture(self, profile_picture: str): if not isinstance(profile_picture, str): raise InvalidTypeException( f"The link to profile picture provided is not a str (type provided is {type(profile_picture)})." ) # TODO: add link validation from google cloud self._profile_picture = profile_picture
def number(self, number: int): if not isinstance(number, int): raise InvalidTypeException( f"The course number provided is not an int (type provided is {type(number)})." ) if not 0 < number < 100000: raise InvalidFormatException( f"The format for course number doesn't match. Expected 0 < number < 100000, got {number}" ) self._number = number
def students(self, students: List[Union[str, ObjectId]]): from api.classes import Student if not isinstance(students, list): raise InvalidTypeException( f"The parameter 'students' provided is not a list (type provided is {type(students)})." ) if students == [] or students == [None]: self._students = list() return if isinstance(students[0], ObjectId): students = [str(student_id) for student_id in students] for student_id in students: if not isinstance(student_id, str): raise InvalidTypeException( f"The parameter student_id {student_id} in students is not a str (type provided is {type(student_id)})." ) try: ObjectId(student_id) except Exception as e: logger.exception( f"Error while validating student id {student_id}") raise e try: if Student.get_by_id(student_id) is None: raise Exception( f"The student with id {student_id} does not exist.") except Exception as e: logger.exception( f"Error while validating the existence of student {student_id}" ) raise e self._students = students
def email(self, email: str): if not isinstance(email, str): raise InvalidTypeException( f"The email provided is not a str (type provided is {type(email)})." ) if not re.match( r"^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$", email): raise InvalidFormatException( f"The email given is not in a valid email format (got {email})" ) self._email = email
def id(self, id: Union[ObjectId, str]): if not isinstance(id, (ObjectId, str)): raise InvalidTypeException( f"The id provided is not a str or bson.objectid.ObjectId (type provided is {type(id)})." ) try: if isinstance(id, str): ObjectId(id) else: id = str(id) except Exception as e: raise InvalidFormatException( f"Cannot convert provided id to bson.ObjectId: {e}") self._id = id
def school_name(self, school_name: str): if not isinstance(school_name, str): raise InvalidTypeException( f"The school name provided is not a str (type provided is {type(school_name)})." ) if not 0 < len(school_name) <= 100: raise InvalidFormatException( f"The length of the school name should not exceed 100 characters (currently: {len(school_name)})" ) if not re.match("[\w \.]{1,50}", school_name, flags=re.UNICODE): raise InvalidFormatException( f"The format for the name doesn't match. Expected only alpha characters, space, or dot, got {school_name}" ) self._school_name = school_name
def principal(self, principal: str): if not isinstance(principal, str): raise InvalidTypeException( f"The principal name provided is not a str (type provided is {type(principal)})." ) if not 0 < len(principal) <= 100: raise InvalidFormatException( f"The length of the name should not exceed 100 characters (currently: {len(principal)})" ) if not re.match("[\w \.]{1,50}", name, flags=re.UNICODE): raise InvalidFormatException( f"The format for the name doesn't match. Expected only alpha characters, space, or dot, got {principal}" ) self._principal = principal
def syllabus(self, syllabus: Tuple[str, str]): if not isinstance(syllabus, tuple): # TODO: logger raise InvalidTypeException( f"The syllabus provided is not a tuple (type provided is {type(syllabus)})" ) if syllabus == (): self._syllabus = syllabus return if (len(syllabus) != 2 or not isinstance(syllabus[0], str) or not isinstance(syllabus[1], str)): # TODO: logger raise InvalidFormatException( f"The format for syllabus does not match: expected Tuple[str, str], got {syllabus}" ) # TODO: add check for a valid syllabus self._syllabus = syllabus
def date_of_birth(self, date_of_birth: str): date_format = "%d-%m-%Y" if not isinstance(date_of_birth, str): raise InvalidTypeException( f"The date of birth provided is not a str (type provided is {type(name)})." ) if date_of_birth == "": self._date_of_birth = "14-03-1879" # Einstein birthdate return try: date_obj = datetime.datetime.strptime(date_of_birth, date_format) except ValueError: raise InvalidFormatException( f"Incorrect data format, should be DD-MM-YYYY (got {date_of_birth})" ) # TODO: check so the date is not in the future self._date_of_birth = date_of_birth
def description(self, description: str): if not isinstance(description, str): raise InvalidTypeException( f"The description provided is not a str (type provided is {type(description)})" ) if not 0 < len(description) <= 500: raise InvalidFormatException( f"The string provided is too long. The description should not exceed 500 characters. (currently: {len(description)})" ) if not re.match( r'[\w \.\+\(\)\[\]\{\}\?\*\&\^\%\$\#\/\'"~<>,:;!-_=@]{1,500}', description, flags=re.UNICODE, ): raise InvalidFormatException( r"The format for description doesn't match. Expected '[\w \.\+\(\)\[\]\{\}\?\*\&\^\%\$\#\/\'\"~<>,:;!-_=@]{1, 500}', got {description}" .format(description=description)) self._description = description
def password(self, password: str): r"""The setter method for the password. Parameters ---------- password : str The new password. If the password is a valid hash, will set it to this value (otherwise, will set it to the hash of the new password). """ if not isinstance(password, (str, bytes)): raise InvalidTypeException( f"Password should be in str or bytes format, got {type(password)}" ) # The password's length is limited to 50 in the endpoint, so if it is larger and matches regex, it is a hash # If any of the conditions are not met, this as a new password, so we encode and hash it # The hashed password should never begin with $2a$ or $2y$, but better to be safe # than sorry :D if not (isinstance(password, bytes) and password.startswith( (b"$2a$", b"$2b$", b"$2y$")) and len(password) == 60): password = hashpw(password.encode("utf-8"), gensalt(prefix=b"2b")) self._password = password