def register_courses(): """Adds a course to the system. Returns ------- dict Flashes, course data from the form """ flashes = list() try: if Course.get_by_department_number(request.form["number"]): course = Course(request.form["department"], request.form["number"], request.form["name"]) else: return error("Course already exists"), 400 except KeyError: return error("Not all fields satisfied."), 400 if Admin.add_course(course=course): logger.info(f"Course {request.form['number']} added") flashes.append("Course added!") return response(flashes), 200 else: flashes.append("There was a problem adding your course") return response(flashes), 400
def activate_account(token: str): """Activates the account (while not authenticated) Parameters ---------- token : str The activation token Returns ------- dict The view response """ student = Student.verify_activation_token(token) if student is None: return error("That is an expired or incorrect link."), 400 else: if request.form["password_confirmation"] == request.form["password"]: if student.activate() and student.set_password( request.form["password"]): logger.info(f"Student {student._id} activated their account") return response(["Account activated!", "Password set!"]), 200 else: return error("Unknown error while activating account"), 400 else: return response(["Passwords don't match!"]), 400 db.students.update({"id": ObjectId(student._id)}, {"$set": { "activated": True }}) return response(["Account activated!"]), 200
def add_assignment(): """Adds new assignment for the class Returns ------- dict The view response """ request.form["assigned_to"].choices = current_user.get_class_names() try: file_list = get_existing_assignment_files() new_assignment = Assignment( date_assigned=datetime.utcnow(), assigned_by=current_user.ID, assigned_to=request.form["assigned_to"], due_by=request.form["due_by"], title=request.form["title"], content=request.form["content"], filenames=file_list, estimated_time=request.form["estimated_time"], # weight=request.form['weight'] ) Course.get_by_id( request.form["assigned_to"]).add_assignment(new_assignment) logger.info(f"Assignment {request.form['title']} added") return response(flashes=["Assignment sent!"]) except KeyError: return error("Not all fields satisfied"), 400
def download_blob(filename, actual_filename): storage_client = storage.Client() bucket = storage_client.bucket("gradder-storage") blob = bucket.blob(filename) blob.download_to_filename(actual_filename) logger.info(f"File {actual_filename} - {filename} downloaded")
def submit(course_id: str, assignment_id: str): """Submit work for an assignment Parameters ---------- course_id : str The ID of the class for which the assignment was set assignment_id : str The ID of the assignment Returns ------- dict The view response """ assignment = db.courses.find_one( {"assignments._id": ObjectId(assignment_id)}, { "_id": 0, "assignments": { "$elemMatch": { "_id": ObjectId(assignment_id) } } }, )["assignments"][0] if assignment is not None and course_id in current_user.courses: try: file_list = [] files = request.files.getlist("files") if files[0].filename: for file_ in files: filename = file_.filename blob = upload_blob( uuid.uuid4().hex + "." + file_.content_type.split("/")[-1], file_, ) file_list.append((blob.name, filename)) submission = Submission( date_submitted=datetime.utcnow(), content=request.form["content"], filenames=file_list, student_id=current_user.id, assignment_id=assignment_id, ) current_user.add_submission(current_user.id, course_id, submission=submission) except KeyError: return error("Not all fields satisfied"), 400 else: logger.info(f"Submission {submission.id} made") return response(["Submission was a success"]), 200 else: return error("No assignment found"), 404
def get_signed_url(filename): storage_client = storage.Client() bucket = storage_client.get_bucket("gradder-storage") blob = bucket.get_blob(filename) logger.info(f"File {filename} opened from assignment") return blob.generate_signed_url(expiration=datetime.utcnow() + timedelta(seconds=3600))
def assignments(): """Get all assignments for the signed in user Returns ------- dict The view response """ logger.info("Accessed all assignments") return response(data={"assignments": current_user.get_assignments()})
def upload_blob(filename: str, file_obj): storage_client = storage.Client() bucket = storage_client.bucket("gradder-storage") blob = bucket.blob(filename) blob.upload_from_file(file_obj, content_type=file_obj.content_type) logger.info(f"File {filename} uploaded") return blob
def logout(): """Logout the user Returns ------- dict The view response """ logger.info("LOGGED OUT: {} {} - ACCESS: {}".format( current_user.first_name, current_user.last_name, current_user._type)) logout_user() return response(["You have been logged out"]), 200
def get_by_email(email: str) -> Teacher: r"""Returns Teacher with a specified email. Parameters --------- email : str Returns ------ Teacher """ try: return Teacher.from_dict(db.teachers.find_one({"email": email})) except: logger.info(f"Error when returning Teacher by email {email}")
def assignments_by_class(course_id: str): """Get assignments for a specific class Parameters ---------- course_id : str The ID of the class Returns ------- dict The view response """ course_assignments = Course.get_by_id(course_id).get_assignments() logger.info(f"All assignments from {course_id}.") return response(data={"assignments": course_assignments})
def to_dict(self) -> Dict[str, str]: r"""Converts the object to a dictionary.""" dictionary = { "email": self.email, "first_name": self.first_name, "last_name": self.last_name, "password": self.password, "activated": self.activated, } try: dictionary["_id"] = ObjectId(self.id) except Exception: logger.info("This user has not been initialized yet.") return dictionary
def get_by_id(id: str) -> Teacher: r"""Returns a Teacher object with a specified id. Parameters --------- id : str ID to look up in the database Returns ------- Teacher """ try: return Teacher.from_dict( db.teachers.find_one({"_id": ObjectId(id)})) except: logger.info(f"Error when returning Teacher by id {id}")
def assignment_by_id(course_id: str, assignment_id: str): """Get an assignment by its ID Parameters ---------- course_id : str The ID of the class assignment_id : str The ID of the assignment Returns ------- dict The view response """ assignments = current_user.get_assignments() assignment = get(assignments, id=assignment_id) logger.info( f"All assignments from {course_id} with assignment id {assignment_id}." ) return response(data={"assignment": assignment})
def add_student(): """Adds a student account to the system and sends an activation email. Returns ------- dict Flashes, student data from the form """ flashes = list() try: if not Student.get_by_email(request.form["email"]): student = Student( request.form["email"], request.form["first_name"], request.form["last_name"], ) student.password(request.form["password"]) except KeyError: return error("Not all fields satisfied"), 400 if student.add(): flashes.append("Student added!") logger.info(f"Student {student.email} added") token = current_user.get_activation_token() app = current_app._get_current_object() msg = Message( app.config["MAIL_SUBJECT_PREFIX"] + " " + "Account Activation Link", sender=app.config["MAIL_SENDER"], recipients=[student.email], ) msg.body = f"""Here is your account activation link: { url_for('student.activate_account', token=token, _external=True) } If you did not register for this account, you can ignore this email. If you need any further assistance, please contact [email protected]. """ mail.send(msg) return response(flashes), 200 else: logger.info(f"Error adding Student {student.email}") flashes.append("There was a problem adding this account"), 400 return response(flashes), 400
def manage_courses_by_id(course_id: str): """Provides options to edit the course. Returns ------- dict Flashes, course data from the form """ flashes = list() course = Course.get_by_id(course_id) if course: if request.form.get("file"): syllabus_file = request.form["file"] filename = syllabus_file.filename blob = upload_blob( uuid.uuid4().hex + "." + syllabus_file.content_type.split("/")[-1], syllabus_file, ) syllabus = (blob.name, filename) course.update_syllabus(syllabus) logger.info(f"Course {course._id} updated") Course.update( request.form.get("department"), request.form.get("number"), request.form.get("name"), request.form.get("teacher"), request.form.get("teacher"), request.form.get("description"), request.form.get("schedule_time"), request.form.get("schedule_days"), request.form.get("syllabus"), request.form.get("student"), ) flashes.append("Course information successfully updated!") return response(flashes), 200 else: return error("Course does not exist"), 404
def enter_info(): """Enters description, date of birth and profile picture for student Returns ------- dict Flashes, student data from the form """ flashes = list() user = Student.get_by_id(current_user.id) if request.form.get("description"): user.description = request.form["description"] flashes.append("Description updated") if request.form.get("date_of_birth"): user.date_of_birth = request.form["date_of_birth"] flashes.append("Date of birth updated") try: profile_picture_file = request.files["profile_picture"] filename = profile_picture_file.filename blob = upload_blob( uuid.uuid4().hex + "." + profile_picture_file.content_type.split("/")[-1], profile_picture_file, ) profile_picture = (blob.name, filename) except KeyError: return error("Not all fields satisfied"), 400 user.profile_picture = profile_picture flashes.append("Profile picture updated") logger.info(f"User info {user.id} updated") return response(flashes), 200
def login(): """Login endpoint. Handles user logins with LoginForm Returns ------- dict The view response """ if current_user.is_authenticated: logger.info(f"The user {current_user.id} is already authenticated.") # TODO: this should definitely be a method in a class current_user_info = { "userName": current_user.first_name + " " + current_user.last_name, "userType": current_user._type, "loggedIn": True, "dob": "", } return response(user_info=current_user_info), 200 elif request.method == "GET": # If it's a GET (i.e., a user hasn't entered any info yet, the user is not logged in) logger.info("The user is not logged in.") return response(user_info={"loggedIn": False}), 200 try: req_data = request.get_json() email = req_data["email"].lower() password = req_data["password"] remember_me = req_data["remember_me"] for scope in [Student, Teacher, Admin, Parent]: logger.info( f"Trying to find {scope.__name__} with email {email}...") user = scope.get_by_email(email) if user is not None: logger.info(f"User: {user.first_name}") if user.validate_password(password): login_user(user, remember_me) logger.info( f"LOGGED IN: {user.first_name} {user.last_name} - ACCESS: {user._type}" ) current_user_info = { "userName": current_user.first_name + " " + current_user.last_name, "userType": current_user._type, "loggedIn": True, "dob": "", } return ( response( flashes=[ "Log in succesful! Redirecting to dashboard..." ], user_info=current_user_info, ), 200, ) logger.info( f"Failed to validate the password for the {scope.__name__} with email {email}" ) return error("Invalid password,"), 400 logger.info(f"Could not find {str(scope)} with email {email}") logger.info(f"Could not find any users with email {email}") return error("The user with this email does not exist."), 400 except (KeyError, TypeError): logger.info("Not all fields satisfied") return error("Not all fields satisfied"), 400
def manage_classes_by_id(course_id: str): """Updates a specified course's information Parameters ------- course_id: str The course ID to look up in the database Returns ------- dict Class data (id and name) Current class description """ course = Course.get_by_id(course_id) syllabus_name = course.get_syllabus_name() try: syllabus = [] if request.form and request.files: syllabus_file = request.files["syllabus_file"] syllabus_name = request.form.get("syllabus_name") description = request.form.get("description") if syllabus_file is not None: blob = upload_blob( uuid.uuid4().hex + "." + syllabus_file.content_type.split("/")[-1], syllabus_file, ) syllabus = [blob.name, syllabus_name] course.update_description(description) course.update_syllabus(syllabus) logger.info(f"Syllabus updated") return response( flashes=["Course information successfully updated!"]) else: print("Specify syllabus information") return error("Please specify the syllabus information"), 400 except KeyError: print("Not all fields satisfied") return error("Not all fields satisfied"), 400 courses = [] for course_id in current_user.courses: course_data = { "id": str(course_id), "name": Course.get_by_id(course_id).name, } courses.append(course_data) return response( flashes=["Course information successfully updated!"], data={ "courses": courses, "current_description": course.description }, )