class OutgoingCalls(db.Model): __tablename__ = 'outgoing_calls' id = db.Column(db.Integer, primary_key=True) contact_id = db.Column(db.Integer, db.ForeignKey('student_contacts.id')) created_at = db.Column(db.DateTime, default=datetime.utcnow)
class QuestionOptions(db.Model): __tablename__ = 'question_options' id = db.Column(db.Integer, primary_key=True) en_text = db.Column(db.Unicode(2000, collation='utf8mb4_unicode_ci')) hi_text = db.Column(db.Unicode(2000, collation='utf8mb4_unicode_ci')) question_id = db.Column(db.Integer, db.ForeignKey('questions.id')) correct = db.Column(db.Boolean, default=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) @staticmethod def create_option(**kwargs): """ Staticmethod to create option for a specific question_id in the database Params: `en_text` : english text of the option, required, str `hi_text` : hindi text of the option, required, str `question_id` : id of the question of the options, required, int `correct` = False, bool Return QuestionOptions instance """ question_option = QuestionOptions(**kwargs) db.session.add(question_option) return question_option
class StudentContact(db.Model): __tablename__ = 'student_contacts' id = db.Column(db.Integer, primary_key=True) contact = db.Column(db.String(10)) main_contact = db.Column(db.Boolean, default=False) student_id = db.Column(db.Integer, db.ForeignKey('students.id')) created_at = db.Column(db.DateTime, default=datetime.utcnow) incoming_calls = db.relationship('IncomingCalls', backref='contact', cascade='all, delete-orphan', lazy='dynamic') outgoing_calls = db.relationship('OutgoingCalls', backref='contact', cascade='all, delete-orphan', lazy='dynamic') outgoing_messages = db.relationship('OutgoingSMS', backref='contact', cascade='all, delete-orphan', lazy='dynamic') def send_sms(self, message, sms_type): """ For sending the message to number associtated with this instance using exotel api. Params: `message` : Contains the message that need to be sent str required `sms_type` : Sending SMS Type Usage: student_contact.send_sms(message) """ exotel.sms(app.config.get("EXOTEL_SMS_NUM"), self.contact, message) # recording the outgoing sms in chanaya outgoing_sms = OutgoingSMS(contact_id=self.id, type=sms_type, text=message) db.session.add(outgoing_sms) db.session.commit() @staticmethod def create(contact, student_id, main_contact=False): """ Function is used for creating a new student_contact record for the student_id. Params: `contact` : '7896121314' Student mobile number `student_id`: '21' Student id `main_contact`: True(default is False) True if we can call on this number to connect with the student else False. """ student_contact = StudentContact(contact=contact, student_id=student_id, main_contact=main_contact) db.session.add(student_contact) db.session.commit()
class OutgoingSMS(db.Model): __tablename__ = 'outgoing_sms' id = db.Column(db.Integer, primary_key=True) contact_id = db.Column(db.Integer, db.ForeignKey('student_contacts.id')) type = db.Column(db.Enum(app.config['OUTGOING_SMS_TYPE']), nullable=False) text = db.Column(db.String(1000), nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow)
class QuestionAttempts(db.Model): __tablename__ = 'attempts' id = db.Column(db.Integer, primary_key=True) enrolment_key_id = db.Column(db.Integer, db.ForeignKey('enrolment_keys.id'), nullable=False) question_id = db.Column(db.Integer, db.ForeignKey('questions.id'), nullable=False) question = db.relationship('Questions') selected_option_id = db.Column( db.Integer, db.ForeignKey('question_options.id')) #to store mcq answer answer = db.Column(db.String(10)) #to store integer value created_at = db.Column(db.DateTime, default=datetime.utcnow) @staticmethod def create_attempts(questions_attempts, enrollment): """ Create the answer attempt made for each enrollment key generated. Params: `enrollment` = EnrolmentKey instance, `question_attempted`: [ { 'question_id' : 23, 'selected_option_id' : 19, }, { 'question_id' : 23, 'answer': '216' } ] """ # recording the answer for question_attempt in questions_attempts: # each attempts for test are for the single enrollment key question_attempt['enrolment_key_id'] = enrollment.id if not question_attempt.get('selected_option_id'): question_attempt['selected_option_id'] = None attempt = QuestionAttempts(**question_attempt) db.session.add(attempt) db.session.commit()
class StudentStageTransition(db.Model): __tablename__ = 'stage_transitions' id = db.Column(db.Integer, primary_key=True) from_stage = db.Column(db.String(100), nullable=False) to_stage = db.Column(db.String(100), nullable=False) notes = db.Column(db.String(1000)) created_at = db.Column(db.DateTime, default=datetime.utcnow) student_id = db.Column(db.Integer, db.ForeignKey('students.id')) student = db.relationship("Student")
class IncomingCalls(db.Model): __tablename__ = 'incoming_calls' id = db.Column(db.Integer, primary_key=True) contact_id = db.Column(db.Integer, db.ForeignKey('student_contacts.id')) call_type = db.Column(db.Enum(app.config['INCOMING_CALL_TYPE']), nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) @staticmethod def create(student_contact, call_type): """ Helps to record all the incoming call made by a students phone number. Params: `student_contact` : StudentContact instance, `call_type`: 'RQC' ['EKG', 'RQC', 'INTERESTED'] """ incoming_call = IncomingCalls(contact_id=student_contact.id, call_type=call_type) db.session.add(incoming_call) db.session.commit()
class EnrolmentKey(db.Model): __tablename__ = 'enrolment_keys' id = db.Column(db.Integer, primary_key=True) key = db.Column(db.String(6), unique=True) test_start_time = db.Column(db.DateTime, nullable=True) test_end_time = db.Column(db.DateTime, nullable=True) student_id = db.Column(db.Integer, db.ForeignKey('students.id')) created_at = db.Column(db.DateTime, default=datetime.utcnow) question_set_id = db.Column(db.Integer, db.ForeignKey('sets.id')) score = db.Column(db.Integer, nullable=True) attempts = db.relationship('QuestionAttempts', backref='enrollment', cascade='all, delete-orphan', lazy='dynamic') question_set = db.relationship("QuestionSet", back_populates="enrolment_key") @staticmethod def generate_key(student_id): """ The method helps to generate a unique enrollment key for the student_id provided and add it to student record. Params: `student_id`: int Return enrollment (object associated to the student_id) """ # generating a new enrollment key ALPHABETS, NUMBERS = string.ascii_uppercase, string.digits enrollment_key = "".join([ random.choice(ALPHABETS) for x in range(3) ]) + "".join([random.choice(NUMBERS) for x in range(3)]) # checking if the enrollment key already exist or not while EnrolmentKey.query.filter_by(key=enrollment_key).first(): enrollment_key = "".join([ random.choice(ALPHABETS) for x in range(3) ]) + "".join([random.choice(NUMBERS) for x in range(3)]) # record the enrollment key in the database enrollment = EnrolmentKey(student_id=student_id, key=enrollment_key) db.session.add(enrollment) db.session.commit() return enrollment def calculate_test_score(self): """ Test Score Calulcation. The method calculate marks for all the questions attempted by each enrollment key(Student). The marks realted to each question are in CONFIG file based on question difficulty level. Update the marks to the score column in the enrollment. """ attempts = self.attempts.all() # get marks config marks_config = app.config['QUESTION_CONFIG']['marks_config'] score = 0 # iterate over each question for attempt in attempts: question = attempt.question is_correct = False # for mcq check if the id which is select is correct = True or not if question.type.value == 'MCQ': selected_option_id = attempt.selected_option_id # for integer_answer strip both attempt answer and answer in the db and check if both are equal or not option = QuestionOptions.query.get(selected_option_id) if option.correct: is_correct = True else: option = question.options.first() correct_answer = option.en_text.strip() student_answer = attempt.answer.strip() if correct_answer == student_answer: is_correct = True # if the flag is true include the score in the score variable if is_correct: question_difficulty = question.difficulty.value mark = marks_config[question_difficulty] score += mark print(score) self.score = score db.session.add(self) db.session.commit() if self.score < app.config['MINIMUM_PASSING_SCORE']: outgoing_sms = app.config['OUTGOING_SMS']['ETF'] else: outgoing_sms = app.config['OUTGOING_SMS']['ETP'] message = outgoing_sms['message'] sms_type = app.config['OUTGOING_SMS_TYPE'](outgoing_sms['sms_type']) student = self.student student.send_sms_to_all_numbers(message, sms_type) def get_question_set(self): """ Generate a question set corresponding to this enrolment key and return the question set instanceself. Note: Also runs the start_test method on the instance. """ self.start_test() question_set, questions = QuestionSet.create_new_set() self.question_set_id = question_set.id db.session.add(self) db.session.commit() return question_set, questions def start_test(self): """ Marks the `test_start_time` parameter of the enrolment key. Also marks the `test_end_time` as `test_start_time` + the time allowed for the test. """ current_datetime = datetime.now() self.test_start_time = current_datetime def end_test(self): """ This records the end time of the test in `test_end_time` attribute. """ self.test_end_time = datetime.now() db.session.add(self) db.session.commit() def is_valid(self): """ The method checks if the key is been used or not if it is not used then the key is valid No params Usage: enrollment.is_valid() Return Boolean value """ current_datetime = datetime.now() # if the test hasn't started of the key it is valid if not self.test_start_time: return True expired_datetime = self.test_start_time + timedelta( seconds=app.config['TEST_DURATION']) # if the test has end for the enrollment key then it is not valid if expired_datetime and expired_datetime <= current_datetime: return False #if the test is ongoing then it is valid elif expired_datetime > current_datetime: return True def is_test_ended(self): """ Checks if the enrollment mkey has been used to give the test or not. No Params Usage: enrollment.is_test_ended() Returns True if the test has ended else False. """ if self.test_end_time: return True return False def in_use(self): """ Check if the enrollment key is already in used or not. No Params Usage: enrollment.in_use() Return Boolean(True when it is being used else False) """ current_datetime = datetime.now() # if it is not used if not self.test_start_time: return False expired_datetime = self.test_start_time + timedelta( seconds=app.config['TEST_DURATION']) # on being used if expired_datetime > current_datetime: return True return False