Best Python code snippet using SeleniumBase
common.py
Source:common.py
...84 sql_str += " AND account_id = '" + user_id + "'"85 sql_str += " AND status = 'true'"8687 # CALL FUNCTION QUERY ONE88 ret = self.postgres.query_fetch_one(sql_str)8990 # RETURN91 return ret9293 def get_account_status(self, account_id):94 """ GET ACCOUNT STATUS """9596 # CREATE SQL QUERY97 sql_str = "SELECT status FROM account WHERE"98 sql_str += " id='{0}'".format(account_id)99100 # CALL FUNCTION QUERY ONE101 res = self.postgres.query_fetch_one(sql_str)102103 if res:104105 return res['status']106107 return 0108109 def update_token_data(self, account_id, request_info):110 """ UPDATE TOKEN DATA """111112 data = {}113 data['update_on'] = time.time()114 data['status'] = True115116 conditions = []117118 conditions.append({119 "col": "account_id",120 "con": "=",121 "val": account_id122 })123124 conditions.append({125 "col": "remote_addr",126 "con": "=",127 "val": request_info.remote_addr128 })129130 conditions.append({131 "col": "platform",132 "con": "=",133 "val": request_info.user_agent.platform134 })135136 conditions.append({137 "col": "browser",138 "con": "=",139 "val": request_info.user_agent.browser140 })141142 conditions.append({143 "col": "version",144 "con": "=",145 "val": request_info.user_agent.version146 })147148 self.postgres.update('account_token', data, conditions)149150 return 1151152 def validate_token(self, token, user_id, request_info):153 """Validate Token"""154155 # CHECK ACCOUNT STATUS156 status = self.get_account_status(user_id)157158 p_status = "status: {0}".format(status)159 syslog.syslog(p_status)160161 if not status:162163 return 0164165 # SET COLUMN FOR RETURN166 columns = ['account_id', 'update_on']167168 # CHECK IF TOKEN EXISTS169 user_data = self.get_user_info(columns, "account_token", user_id, token)170171 p_user_data = "user_data: {0}".format(user_data)172 syslog.syslog(p_user_data)173174 self.postgres = PostgreSQL()175176 # CHECK IF COLUMN EXIST,RETURN 0 IF NOT177 if user_data:178179 dt1 = datetime.fromtimestamp(user_data['update_on'])180 dt2 = datetime.fromtimestamp(time.time())181 dateutil.relativedelta.relativedelta(dt2, dt1)182183 rd1 = dateutil.relativedelta.relativedelta(dt2, dt1)184 # print(rd1.years, rd1.months, rd1.days, rd1.hours, rd1.minutes, rd1.seconds)185186 if rd1.years or rd1.months or rd1.days or rd1.hours:187188 return 0189190 if rd1.minutes > 30:191192 return 0193194 else:195196 return 0197198 self.update_token_data(user_id, request_info)199 # RETURN200 return 1201202 # COUNT DATA203 def count_data(self, datas, column, item):204 """Return Data Count"""205206 # INITIALIZE207 count = 0208209 # LOOP DATAS210 for data in datas:211212 # CHECK OF DATA213 if data[column] == item:214215 # INCREASE COUNT216 count += 1217218 # RETURN219 return count220221 def set_return(self, datas):222 """Set Return"""223 ret_data = {}224 ret_data['data'] = []225 for data in datas:226 ret_data['data'].append(data['value'])227228 return ret_data229230 def check_request_json(self, query_json, important_keys):231 """Check Request Json"""232 query_json = simplejson.loads(simplejson.dumps(query_json))233234 for imp_key in important_keys.keys():235236 if imp_key not in query_json:237 return 0238239 if type(query_json.get(imp_key)):240241 if type(query_json[imp_key]) != type(important_keys[imp_key]):242243 return 0244245 else:246247 return 0248249 return 1250251 def limits(self, rows, limit, page):252 """Limits"""253 skip = int((page - 1) * limit)254255 limit = skip + limit256257 return rows[skip:limit]258259 def param_filter(self, temp_datas, params, checklist):260 """Parameter Filter"""261 if not params:262263 return temp_datas264265 param_datas = []266 param_datas = temp_datas267268 output = []269270 i = 0271272 for param in params:273 key = checklist[i]274275 i += 1276277 for data in param_datas:278279 if self.filter_checker(str(param), str(data[key])):280281 output.append(data)282283 return output284285 def filter_checker(self, pattern, value):286 """Check Filter"""287 if '*' in pattern:288 pattern = pattern.replace('.', r'\.')289 if pattern == "*":290 pattern = "."291292 if not pattern[0] == "*" and pattern != ".":293 pattern = "^" + str(pattern)294295 if pattern[-1] == "*":296 pattern = pattern[:-1] + '+'297298 if not pattern[-1] == "+" and pattern != ".":299 pattern = str(pattern) + '$'300301 if pattern[0] == "*":302 pattern = '.?' + pattern[1:]303304 pattern = pattern.replace('*', '.+')305306 # print("pattern: ", pattern)307308 try:309310 if not re.findall(pattern, value, re.IGNORECASE):311312 return 0313314 except:315316 return 0317318 else:319320 if not value == pattern:321322 return 0323324 return 1325326 def isfloat(self, data):327 """Check if float"""328 try:329 if data == "infinity":330 return False331332 float(data)333 except ValueError:334 return False335 else:336 return True337338 def isint(self, data):339 """Check if Integer"""340 try:341 if data == "infinity":342 return False343344 tmp_data1 = float(data)345 tmp_data2 = int(tmp_data1)346 except ValueError:347 return False348 else:349 return tmp_data1 == tmp_data2350351 def file_replace(self, filename):352 """ File Naming """353354 file_name = filename.split(".")[0]355356 if "_" in file_name:357358 suffix = file_name.split("_")[-1]359360 if suffix.isdigit():361 new_name = filename.replace(suffix, str(int(suffix) + 1))362 else:363 new_name = filename.replace(suffix, str(suffix+"_1"))364 else:365 new_name = filename.replace(file_name, str(file_name+"_1"))366367 return new_name368369 def format_filter(self, datas):370 """ Return Filter in Format """371372 tmp = []373374 for data in datas:375376 tmp.append({377 "label": data,378 "value": data379 })380381 return tmp382383 def data_filter(self, datas, key):384 """Filter Data"""385 temp_data = []386387 if datas and key:388389 key = "{0}s".format(key)390391 data_list = []392 for data in datas[key]:393394 data_list.append(data)395396 for data in data_list:397 if data in [True, False]:398 data = "{0}".format(data)399400 if key == "statuss":401402 if data == "True":403 data = "Enabled"404405 if data == "False":406 data = "Disabled"407408 temp_data.append({409 "label": data,410 "value": data411 })412413414 return temp_data415416 def days_update(self, timestamp, count=0, add=False):417 """Days Update"""418 try:419420 named_tuple = time.localtime(int(timestamp))421422 # GET YEAR MONTH DAY423 year = int(time.strftime("%Y", named_tuple))424 month = int(time.strftime("%m", named_tuple))425 day = int(time.strftime("%d", named_tuple))426427 # Date in tuple428 date_tuple = (year, month, day, 0, 0, 0, 0, 0, 0)429430 local_time = time.mktime(date_tuple)431 orig = datetime.fromtimestamp(local_time)432433 if add:434435 new = orig + timedelta(days=count)436437 else:438439 new = orig - timedelta(days=count)440441 return new.timestamp()442443 except:444445 return 0446447 def check_progress(self, data):448 """ RETURN PROGRESS """449450 assert data, "Data is a must."451452 answer = [dta['answer'] for dta in data]453 total = len(answer)454 not_answer = [None, '', []]455 total_answer = len([ans for ans in answer if ans not in not_answer])456457 average = self.format_progress((total_answer / total) * 100)458459 return average460461 def format_progress(self, progress):462 """ Format Progress """463464 progress = round(progress, 2)465 if progress.is_integer():466 return int(progress)467468 return progress469470 def validate_user(self, userid, user_role):471 """ VALIDATE USER TYPE """472473 sql1 = "SELECT role_id FROM account_role WHERE"474 sql1 += " account_id='{0}'".format(userid)475476 sql_str = "SELECT role_name FROM role WHERE"477 sql_str += " role_id IN ({0})".format(sql1)478479 role = self.postgres.query_fetch_one(sql_str)480 role_name = role['role_name']481482 if role_name == user_role:483484 return 1485486 return 0487488 def check_answer(self, question_id, answer, userid=None):489 """Return Answer"""490491 # DATA492 sql_str = "SELECT e.*, cq.* FROM course_question cq"493 sql_str += " LEFT JOIN exercise e ON cq.exercise_id = e.exercise_id"494 sql_str += " WHERE course_question_id = '{0}'".format(question_id)495 result = self.postgres.query_fetch_one(sql_str)496497 data = {}498499 if result:500501 if result['question_type'] == 'FITBT':502503 question = result['question']['question'].replace("<ans>", "")504505 if question == answer:506507 if result['moving_allowed'] is False:508 data['message'] = "You cannot skip this question"509 data['isCorrect'] = False510511 else:512 data['message'] = "No answer given"513 data['isCorrect'] = False514515 if userid:516 data['message'] = self.translate(userid, data['message'])517518 return data519520 if result['question_type'] == 'FITBD':521522 question = result['question']['question'].replace("<ans>", "")523524 if question == answer:525 data['message'] = "No answer given"526 data['isCorrect'] = False527528 if userid:529 data['message'] = self.translate(userid, data['message'])530531 return data532533 if answer in [None,'', str( [""]), str([]), str(['']), [], ['']]:534 if result['moving_allowed'] is False:535 data['message'] = "You cannot skip this question"536 data['isCorrect'] = False537 else:538 data['message'] = "No answer given"539 data['isCorrect'] = False540541 if userid:542 data['message'] = self.translate(userid, data['message'])543544 return data545546 # FITBD547 if result['question_type'] in ['FITBD']:548549 correct_answer = result['correct_answer']['answer']550551 if answer in correct_answer:552 data['message'] = result['correct']553 data['isCorrect'] = True554 else:555 data['message'] = result['incorrect']556 data['isCorrect'] = False557558 if userid:559 data['message'] = self.translate(userid, data['message'])560561 return data562563 if result['question_type'] in ['MULRE', 'MATCH']:564565 correct_answer = result['correct_answer']['answer']566567 if len(correct_answer) != len(answer):568 data['message'] = result['incorrect']569 data['isCorrect'] = False570571 if userid:572 data['message'] = self.translate(userid, data['message'])573574 return data575576 # MATCH577 if result['question_type'] == 'MATCH':578 if answer == correct_answer:579 data['message'] = result['correct']580 data['isCorrect'] = True581 else:582 data['message'] = result['incorrect']583 data['isCorrect'] = False584585 if userid:586 data['message'] = self.translate(userid, data['message'])587588 return data589590 # MULRE591 if result['shuffle_answers'] is False:592 if answer == correct_answer:593 data['message'] = result['correct']594 data['isCorrect'] = True595 else:596 data['message'] = result['incorrect']597 data['isCorrect'] = False598599 else:600 score = 0601 for ans in answer:602 if ans in correct_answer:603 score += 1604605 if score == len(correct_answer):606 data['message'] = result['correct']607 data['isCorrect'] = True608 else:609 data['message'] = result['incorrect']610 data['isCorrect'] = False611612 if userid:613 data['message'] = self.translate(userid, data['message'])614615 return data616617 ans = {}618 ans["answer"] = answer619620 if str(result['correct_answer']) == str(ans):621 data['message'] = result['correct']622 data['isCorrect'] = True623 else:624 data['message'] = result['incorrect']625 data['isCorrect'] = False626627 if userid:628629 data['message'] = self.translate(userid, data['message'])630631 return data632633 def translate(self, user_id, message):634 """ Return Translation """635636 sql_str = "SELECT language FROM account WHERE"637 sql_str += " id='{0}'".format(user_id)638 language = self.postgres.query_fetch_one(sql_str)639640 if language['language'] != 'en-US':641642 message = "".join(re.findall(r'[a-zA-Z\ ]', message))643644 sql_str = "SELECT translation FROM translations WHERE word_id=("645 sql_str += "SELECT word_id FROM words WHERE"646 sql_str += " name = '{0}') AND ".format(message)647 sql_str += "language_id=(SELECT language_id FROM language WHERE "648 sql_str += "initial='{0}')".format(language['language'])649650 translate = self.postgres.query_fetch_one(sql_str)651652 if translate:653 message = translate['translation']654655 return message656657 def translate_course(self, user_id, course_id):658 """ Return Course Translation """659660 data = {}661 sql_str = "SELECT * FROM course WHERE course_id = '{0}'".format(course_id)662 result = self.postgres.query_fetch_one(sql_str)663664 data['course_name'] = self.translate(user_id, result['course_name'])665 data['description'] = self.translate(user_id, result['description'])666667 return data668669 def trim_url(self, url):670 """ Return domain url """671672 # FORMAT URL673 trim = re.compile(r"https?://(www\.)?")674 return trim.sub('', url).strip().strip('/')675676 def can_access_tutorenv(self, user_id):677 """ Check access rights """678679 sql_str = "SELECT * FROM account_role ac"680 sql_str += " LEFT JOIN role r ON ac.role_id = r.role_id"681 sql_str += " WHERE account_id = '{0}'".format(user_id)682 result = self.postgres.query_fetch_one(sql_str)683684 roles = ['MANAGER', 'TUTOR']685 if result['role_name'].upper() in roles:686 return 1687688 return 0689690 def check_question(self, question_id):691 """ Validate Question ID """692693 # DATA694 sql_str = "SELECT * FROM course_question"695 sql_str += " WHERE course_question_id = '{0}'".format(question_id)696 result = self.postgres.query_fetch_one(sql_str)697 if result:698 return 1699700 return 0701702 def allowed_file_type(self, filename):703 """ Check Allowed File Extension """704705 allowed_extensions = set(['csv'])706707 return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowed_extensions708709 def course_header(self):710 """ RETURN COURSE COLUMN """711712 return [713 "Course ID",714 "Course Name",715 "Course Description",716 "Course Difficulty Level",717 "Course Requirements",718719 "Section ID",720 "Section Name",721 "Section Description",722 "Section Difficulty Level",723724 "Subsection ID",725 "Subsection Name",726 "Subsection Description",727 "Subsection Difficulty Level",728729 "Exercise ID",730 "Exercise Number",731 "Exercise Question Type",732 "Exercise Tags",733 "Exercise Description",734 "Exercise Draw By Tag",735 "Exercise Editing Allowed",736 "Exercise Help",737 "Exercise Instant Feedback",738 "Exercise Moving Allowed",739 "Exercise Number to Draw",740 "Exercise Passing Criterium",741 "Exercise Save Seed",742 "Exercise Seed",743 "Exercise Shuffled",744 "Exercise Text Before Start",745 "Exercise Text After End",746 "Exercise Timed Limit",747 "Exercise Timed Type",748749 "Question ID",750 "Question",751 "Question Type",752 "Question Tags",753 "Question Choices",754 "Question Shuffle Options",755 "Question Shuffle Answers",756 "Question Num Eval",757 "Question Correct Answer",758 "Question Correct",759 "Question Incorrect",760 "Question Feedback",761 "Question Description"762 ]763764 def fetch_course_details(self, userid, course_id):765 """ Return Course Details """766767 sql_str = "SELECT * FROM course_master WHERE"768 sql_str += " course_id='{0}'".format(course_id)769 result = self.postgres.query_fetch_all(sql_str)770771 for res in result:772 res['course_name'] = self.translate(userid, res['course_name'])773 res['description'] = self.translate(userid, res['description'])774775 return result776777 def check_headers(self, csv_data, headers):778 """ CHECK COLUMN """779780 for key in self.course_header():781782 if not key in headers:783784 return 0785786 return 1787788 def run_update(self, csv_data):789 """ CONVERT CSV TO JSON """790791 json_data = {}792 json_data['status'] = 'ok'793794 course_id = ""795 section_id = ""796 subsection_id = ""797798 for row in csv_data:799800 # COURSE801 if row['Course ID'] or row['Course Name']:802803 course_id = self.iu_course(row)804805 if not course_id:806807 json_data["alert"] = "Course already exist!"808 json_data['status'] = 'Failed'809810 return json_data811812 # CHECK IF COURSE IS ALREADY IN USE813 if not self.use_course(course_id):814815 json_data["alert"] = "Course is in use!"816 json_data['status'] = 'Failed'817818 return json_data819820 # SECTION821 if row['Section ID'] or row['Section Name']:822823 section_id = self.iu_section(row, course_id)824825 if not section_id:826827 json_data["alert"] = "Section {0} already exist!".format(row['Section Name'])828 json_data['status'] = 'Failed'829830 return json_data831832 # SUBSECTION833 if row['Subsection ID'] or row['Subsection Name']:834835 subsection_id = self.iu_subsection(row, course_id, section_id)836837 if not subsection_id:838839 json_data["alert"] = "Subsection {0} already exist!".format(row['Subsection Name'])840 json_data['status'] = 'Failed'841842 return json_data843844 # EXERCISE845 if row['Exercise ID'] or row['Exercise Number']:846847 exercise_id = self.iu_exercise(row, course_id, section_id, subsection_id)848849 if not exercise_id:850851 json_data["alert"] = "Exercise {0} already exist!".format(row['Exercise Number'])852 json_data['status'] = 'Failed'853854 return json_data855856 # QUESTION857 # if row['Question ID'] or row['Question']:858859 # question_id = self.iu_question(row, course_id, section_id, subsection_id, exercise_id)860861 # if not question_id:862863 # json_data["alert"] = "Question {0} already exist!".format(row['Question'])864 # json_data['status'] = 'Failed'865866 # return json_data867868 return json_data869870 def iu_course(self, data):871 """ UPDATE COURSE """872873 if data['Course ID']:874875 return self.update_course(data)876877 if data['Course Name']:878879 sql_str = "SELECT * FROM course WHERE"880 sql_str += " course_name ='{0}'".format(data['Course Name'])881882 cdata = self.postgres.query_fetch_one(sql_str)883884 if cdata:885886 return 0887888 updated_data = {}889890 data['Course Difficulty Level'] = 1891892 updated_data['course_name'] = data['Course Name']893 if data['Course Description']:894 updated_data['description'] = data['Course Description']895 if data['Course Difficulty Level']:896 updated_data['difficulty_level'] = data['Course Difficulty Level']897 if data['Course Requirements']:898 updated_data['requirements'] = data['Course Requirements']899 updated_data['status'] = True900 updated_data['created_on'] = time.time()901902 course_id = self.postgres.insert('course', updated_data, 'course_id')903904 return course_id905906 def iu_section(self, data, course_id):907 """ UPDATE SECTION """908909 if not data['Section Name'] and data['Section ID']:910911 conditions = []912913 conditions.append({914 "col": "section_id",915 "con": "=",916 "val": data['Section ID']917 })918919 self.postgres.delete('section', conditions)920921 if data['Section ID']:922923 updated_data = {}924925 updated_data['difficulty_level'] = 1926927 updated_data['section_name'] = data['Section Name']928 if data['Section Description']:929 updated_data['description'] = data['Section Description']930 if data['Section Difficulty Level']:931 updated_data['difficulty_level'] = data['Section Difficulty Level']932933 # INIT CONDITION934 conditions = []935936 # CONDITION FOR QUERY937 conditions.append({938 "col": "course_id",939 "con": "=",940 "val": course_id941 })942943 conditions.append({944 "col": "section_id",945 "con": "=",946 "val": data['Section ID']947 })948949 self.postgres.update('section', updated_data, conditions)950951 return data['Section ID']952953 if data['Section Name']:954955 sql_str = "SELECT * FROM section WHERE"956 sql_str += " section_name ='{0}'".format(data['Section Name'])957958 sdata = self.postgres.query_fetch_one(sql_str)959960 if sdata:961962 return 0963964 updated_data = {}965966 updated_data['difficulty_level'] = 1967968 updated_data['course_id'] = course_id969 updated_data['section_id'] = self.sha_security.generate_token(False)970 updated_data['section_name'] = data['Section Name']971 if data['Section Description']:972 updated_data['description'] = data['Section Description']973 if data['Section Difficulty Level']:974 updated_data['difficulty_level'] = data['Section Difficulty Level']975 updated_data['status'] = True976 updated_data['created_on'] = time.time()977978 section_id = self.postgres.insert('section', updated_data, 'section_id')979980 return section_id981982 def iu_subsection(self, data, course_id, section_id):983 """ UPDATE SUBSECTION """984985 if not data['Subsection Name'] and data['Subsection ID']:986987 conditions = []988989 conditions.append({990 "col": "subsection_id",991 "con": "=",992 "val": data['Subsection ID']993 })994995 self.postgres.delete('subsection', conditions)996997 if data['Subsection ID']:998999 updated_data = {}10001001 updated_data['difficulty_level'] = 110021003 updated_data['subsection_name'] = data['Subsection Name']1004 if data['Subsection Description']:1005 updated_data['description'] = data['Subsection Description']1006 if data['Subsection Difficulty Level']:1007 updated_data['difficulty_level'] = data['Subsection Difficulty Level']10081009 # INIT CONDITION1010 conditions = []10111012 # CONDITION FOR QUERY1013 conditions.append({1014 "col": "course_id",1015 "con": "=",1016 "val": course_id1017 })10181019 conditions.append({1020 "col": "section_id",1021 "con": "=",1022 "val": section_id1023 })10241025 conditions.append({1026 "col": "subsection_id",1027 "con": "=",1028 "val": data['Subsection ID']1029 })10301031 self.postgres.update('subsection', updated_data, conditions)10321033 return data['Subsection ID']10341035 if data['Subsection Name']:10361037 sql_str = "SELECT * FROM subsection WHERE"1038 sql_str += " subsection_name ='{0}'".format(data['Subsection Name'])10391040 ssdata = self.postgres.query_fetch_one(sql_str)10411042 if ssdata:10431044 return 010451046 updated_data = {}10471048 updated_data['difficulty_level'] = 110491050 updated_data['course_id'] = course_id1051 updated_data['section_id'] = section_id1052 updated_data['subsection_id'] = self.sha_security.generate_token(False)1053 updated_data['subsection_name'] = data['Subsection Name']1054 if data['Subsection Description']:1055 updated_data['description'] = data['Subsection Description']1056 if data['Subsection Difficulty Level']:1057 updated_data['difficulty_level'] = data['Subsection Difficulty Level']1058 updated_data['status'] = True1059 updated_data['created_on'] = time.time()10601061 subsection_id = self.postgres.insert('subsection', updated_data, 'subsection_id')10621063 return subsection_id10641065 def iu_exercise(self, data, course_id, section_id, subsection_id):1066 """ UPDATE COURSE """10671068 if not data['Exercise Number'] and data['Exercise ID']:10691070 conditions = []10711072 conditions.append({1073 "col": "exercise_id",1074 "con": "=",1075 "val": data['Exercise ID']1076 })10771078 self.postgres.delete('course_question', conditions)1079 self.postgres.delete('exercise', conditions)10801081 return data['Exercise ID']10821083 if data['Exercise ID']:10841085 updated_data = {}1086 updated_data['exercise_number'] = data['Exercise Number']10871088 # CODE FOR QUESTIONS10891090 if data['Exercise Question Type']:1091 updated_data['question_types'] = json.dumps(data['Exercise Question Type'].replace("\'", "").replace("\"", "")[1:-1].split(", "))1092 if data['Exercise Tags']:1093 updated_data['tags'] = json.dumps(data['Exercise Tags'].replace("\'", "").replace("\"", "")[1:-1].split(", "))1094 if data['Exercise Description']:1095 updated_data['description'] = data['Exercise Description']1096 if data['Exercise Draw By Tag']:1097 updated_data['draw_by_tag'] = data['Exercise Draw By Tag'].upper() == 'TRUE'1098 if data['Exercise Editing Allowed']:1099 updated_data['editing_allowed'] = data['Exercise Editing Allowed'].upper() == 'TRUE'1100 if data['Exercise Help']:1101 updated_data['help'] = data['Exercise Help'].upper() == 'TRUE'1102 if data['Exercise Instant Feedback']:1103 updated_data['instant_feedback'] = data['Exercise Instant Feedback'].upper() == 'TRUE'1104 if data['Exercise Moving Allowed']:1105 updated_data['moving_allowed'] = data['Exercise Moving Allowed'].upper() == 'TRUE'1106 if data['Exercise Number to Draw']:1107 updated_data['number_to_draw'] = data['Exercise Number to Draw']1108 if data['Exercise Passing Criterium']:1109 updated_data['passing_criterium'] = data['Exercise Passing Criterium']1110 if data['Exercise Save Seed']:1111 updated_data['save_seed'] = data['Exercise Save Seed'].upper() == 'TRUE'1112 if data['Exercise Seed']:1113 updated_data['seed'] = data['Exercise Seed']1114 if data['Exercise Shuffled']:1115 updated_data['shuffled'] = data['Exercise Shuffled'].upper() == 'TRUE'1116 if data['Exercise Text Before Start']:1117 updated_data['text_before_start'] = data['Exercise Text Before Start']1118 if data['Exercise Text After End']:1119 updated_data['text_after_end'] = data['Exercise Text After End']1120 if data['Exercise Timed Limit']:1121 updated_data['timed_limit'] = data['Exercise Timed Limit']1122 if data['Exercise Timed Type']:1123 updated_data['timed_type'] = data['Exercise Timed Type']112411251126 # INIT CONDITION1127 conditions = []11281129 # CONDITION FOR QUERY1130 conditions.append({1131 "col": "course_id",1132 "con": "=",1133 "val": course_id1134 })11351136 conditions.append({1137 "col": "section_id",1138 "con": "=",1139 "val": section_id1140 })11411142 conditions.append({1143 "col": "subsection_id",1144 "con": "=",1145 "val": subsection_id1146 })11471148 conditions.append({1149 "col": "exercise_id",1150 "con": "=",1151 "val": data['Exercise ID']1152 })11531154 self.postgres.update('exercise', updated_data, conditions)11551156 # ADD QUESTION to COURSE QUESTION1157 self.add_course_question(data['Exercise ID'])11581159 return data['Exercise ID']11601161 updated_data = {}1162 updated_data['draw_by_tag'] = False1163 updated_data['editing_allowed'] = True1164 updated_data['help'] = True1165 updated_data['instant_feedback'] = True1166 updated_data['moving_allowed'] = True1167 updated_data['number_to_draw'] = 101168 updated_data['passing_criterium'] = 51169 updated_data['save_seed'] = True1170 updated_data['seed'] = 101171 updated_data['shuffled'] = False1172 updated_data['timed_limit'] = 3001173 updated_data['timed_type'] = 'per_question'11741175 updated_data['course_id'] = course_id1176 updated_data['section_id'] = section_id1177 updated_data['subsection_id'] = subsection_id1178 updated_data['exercise_id'] = self.sha_security.generate_token(False)1179 updated_data['exercise_number'] = data['Exercise Number']1180 if data['Exercise Question Type']:1181 updated_data['question_types'] = json.dumps(data['Exercise Question Type'].replace("\'", "").replace("\"", "")[1:-1].split(", "))1182 if data['Exercise Tags']:1183 updated_data['tags'] = json.dumps(data['Exercise Tags'].replace("\'", "").replace("\"", "")[1:-1].split(", "))1184 if data['Exercise Description']:1185 updated_data['description'] = data['Exercise Description']1186 if data['Exercise Draw By Tag']:1187 updated_data['draw_by_tag'] = data['Exercise Draw By Tag'].upper() == 'TRUE'1188 if data['Exercise Description']:1189 updated_data['editing_allowed'] = data['Exercise Editing Allowed'].upper() == 'TRUE'1190 if data['Exercise Help']:1191 updated_data['help'] = data['Exercise Help'].upper() == 'TRUE'1192 if data['Exercise Instant Feedback']:1193 updated_data['instant_feedback'] = data['Exercise Instant Feedback'].upper() == 'TRUE'1194 if data['Exercise Moving Allowed']:1195 updated_data['moving_allowed'] = data['Exercise Moving Allowed'].upper() == 'TRUE'1196 if data['Exercise Number to Draw']:1197 updated_data['number_to_draw'] = data['Exercise Number to Draw']1198 if data['Exercise Passing Criterium']:1199 updated_data['passing_criterium'] = data['Exercise Passing Criterium']1200 if data['Exercise Save Seed']:1201 updated_data['save_seed'] = data['Exercise Save Seed'].upper() == 'TRUE'1202 if data['Exercise Seed']:1203 updated_data['seed'] = data['Exercise Seed']1204 if data['Exercise Shuffled']:1205 updated_data['shuffled'] = data['Exercise Shuffled'].upper() == 'TRUE'1206 if data['Exercise Text Before Start']:1207 updated_data['text_before_start'] = data['Exercise Text Before Start']1208 if data['Exercise Text After End']:1209 updated_data['text_after_end'] = data['Exercise Text After End']1210 if data['Exercise Timed Limit']:1211 updated_data['timed_limit'] = data['Exercise Timed Limit']1212 if data['Exercise Timed Type']:1213 updated_data['timed_type'] = data['Exercise Timed Type']1214 updated_data['created_on'] = time.time()12151216 exercise_id = self.postgres.insert('exercise', updated_data, 'exercise_id')12171218 # ADD QUESTION to COURSE QUESTION1219 self.add_course_question(exercise_id)12201221 return exercise_id12221223 def iu_question(self, data, course_id, section_id, subsection_id, exercise_id):1224 """ UPDATE QUESTION """12251226 question_id = self.get_question_id(data)12271228 sql_str = "SELECT question_id FROM course_question WHERE"1229 sql_str += " course_id='{0}'".format(course_id)1230 sql_str += " AND section_id='{0}'".format(section_id)1231 sql_str += " AND subsection_id='{0}'".format(subsection_id)1232 sql_str += " AND exercise_id='{0}'".format(exercise_id)1233 sql_str += " AND question_id='{0}'".format(question_id)12341235 if not self.postgres.query_fetch_one(sql_str):12361237 qtype = data['Question Type']12381239 temp = {}1240 temp['question_id'] = question_id1241 temp['course_question_id'] = self.sha_security.generate_token(False)1242 temp['course_id'] = course_id1243 temp['section_id'] = section_id1244 temp['subsection_id'] = subsection_id1245 temp['exercise_id'] = exercise_id1246 temp['question_type'] = data['Question Type']1247 temp['tags'] = json.dumps(data['Question Tags'].replace("\'", "").replace("\"", "")[1:-1].split(", "))1248 temp['shuffle_options'] = ""1249 temp['shuffle_answers'] = ""1250 temp['feedback'] = ""1251 array_choice = []12521253 if qtype == 'FITBT':12541255 ans = "".join(re.findall(r'[^\{$\}]', data['Question Correct Answer']))1256 answer = {}1257 answer['answer'] = data['Question'].replace("<ans>", str(ans))12581259 quest = {}1260 quest['question'] = data['Question']12611262 temp['correct_answer'] = json.dumps(answer)1263 temp['question'] = json.dumps(quest)12641265 elif qtype == 'FITBD':12661267 answer = {}1268 answer['answer'] = data['Question']12691270 allans = "".join(re.findall(r'[^\{$\}]', data['Question Correct Answer'])).split(", ")12711272 for ans in allans:12731274 correct_answer = answer['answer'].replace("[blank]", ans, 1)1275 answer['answer'] = correct_answer12761277 quest = {}1278 quest['question'] = data['Question'].replace("[blank]", "<ans>")12791280 temp['correct_answer'] = json.dumps(answer)1281 temp['question'] = json.dumps(quest)12821283 elif qtype == 'MULCH':12841285 choices = "".join(re.findall(r'[^\{$\}]', data['Question Choices']))1286 choices = choices.split(", ")12871288 for choice in choices:12891290 array_choice.append(choice)12911292 answer = {}1293 answer['answer'] = data['Question Correct Answer']12941295 quest = {}1296 quest['question'] = data['Question']12971298 temp['correct_answer'] = json.dumps(answer)1299 temp['question'] = json.dumps(quest)13001301 elif qtype == 'MATCH':13021303 temp['shuffle_options'] = data['Question Shuffle Options']1304 temp['shuffle_answers'] = data['Question Shuffle Answers']13051306 allans = "".join(re.findall(r'[^\{$\}]', data['Question Correct Answer'])).split(", ")1307 answer = {}1308 answer['answer'] = allans13091310 quest_data = data['Question'].replace("\"", "")1311 allquest = "".join(re.findall(r'[^\{$\}]', quest_data)).split(", ")1312 quest = {}1313 quest['question'] = allquest13141315 array_choice = "".join(re.findall(r'[^\{$\}]', data['Question Choices']))1316 array_choice = array_choice.split(", ")1317 temp['correct_answer'] = json.dumps(answer)1318 temp['question'] = json.dumps(quest)13191320 elif qtype == 'MULRE':13211322 temp['shuffle_options'] = data['Question Shuffle Options']1323 temp['shuffle_answers'] = data['Question Shuffle Answers']13241325 allans = data['Question Correct Answer'].replace("\"", "")1326 allans = "".join(re.findall(r'[^\{$\}]', allans)).split(", ")1327 answer = {}1328 answer['answer'] = allans13291330 quest = {}1331 quest['question'] = data['Question']13321333 array_choice = data['Question Choices'].replace("\"", "")1334 array_choice = "".join(re.findall(r'[^\{$\}]', array_choice))1335 array_choice = array_choice.split(", ")1336 temp['correct_answer'] = json.dumps(answer)1337 temp['question'] = json.dumps(quest)13381339 if data['Question Description']:13401341 temp['description'] = data['Question Description']13421343 else:1344 temp['description'] = "Lorem ipsum dolor sit amet, consectetur "1345 temp['description'] += "adipiscing elit, sed do eiusmod tempor "1346 temp['description'] += "incididunt ut labore et dolore magna aliqua."13471348 temp['choices'] = json.dumps(array_choice)1349 temp['correct'] = data['Question Correct']1350 temp['incorrect'] = data['Question Incorrect']1351 temp['status'] = True1352 temp['num_eval'] = data['Question Num Eval'].upper() == 'TRUE'1353 temp['created_on'] = time.time()13541355 self.postgres.insert('course_question', temp, 'course_question_id')13561357 return question_id13581359 def add_course_question(self, exercise_id):1360 """ Add Question for Exercise """13611362 sql_str = "SELECT * FROM exercise WHERE exercise_id='{0}'".format(exercise_id)1363 result = self.postgres.query_fetch_one(sql_str)13641365 if result:13661367 questions = []1368 if result['shuffled'] is True:13691370 # SELECT QUESTION BY QUESTION TYPE AND TAGS1371 tags = []1372 if result['draw_by_tag'] is True:1373 tags = result['tags']13741375 qtypes = result['question_types']1376 number_to_draw = result['number_to_draw']1377 questions = self.generate_random_questions(qtypes, int(number_to_draw), tags)1378 # questionnaires = self.get_questions_by_condition(qtypes, tags)1379 # questions = self.select_random_questions(questionnaires, number_to_draw, qtypes)13801381 # INSERT TO COURSE QUESTION TABLE1382 for question in questions:13831384 qdata = self.get_question_by_id(question)13851386 if qdata:13871388 tmp = {}1389 tmp['course_question_id'] = self.sha_security.generate_token(False)1390 tmp['course_id'] = result['course_id']1391 tmp['section_id'] = result['section_id']1392 tmp['subsection_id'] = result['subsection_id']1393 tmp['exercise_id'] = exercise_id1394 tmp['question_id'] = question1395 tmp['question'] = json.dumps(qdata['question'])1396 tmp['question_type'] = qdata['question_type']1397 tmp['tags'] = json.dumps(qdata['tags'])1398 tmp['choices'] = json.dumps(qdata['choices'])1399 tmp['num_eval'] = qdata['num_eval']1400 tmp['correct_answer'] = json.dumps(qdata['correct_answer'])1401 tmp['correct'] = qdata['correct']1402 tmp['incorrect'] = qdata['incorrect']14031404 if qdata['feedback']:1405 tmp['feedback'] = qdata['feedback']14061407 if qdata['shuffle_options']:1408 tmp['shuffle_options'] = qdata['shuffle_options']14091410 if qdata['shuffle_answers']:1411 tmp['shuffle_answers'] = qdata['shuffle_answers']14121413 tmp['description'] = qdata['description']1414 tmp['status'] = qdata['status']1415 tmp['created_on'] = time.time()14161417 self.postgres.insert('course_question', tmp, 'course_question_id')141814191420 def get_questions_by_condition(self, question_types, tags):1421 """ Return Question by type and tags """14221423 qtype = ','.join("'{0}'".format(qtype) for qtype in question_types)1424 tag = '"tags"'14251426 sql_str = "SELECT * FROM questions WHERE question_type IN ({0})".format(qtype)1427 if tags:1428 tags = ', '.join('"{0}"'.format(tag) for tag in tags)1429 sql_str += " AND CAST({0} AS text) = '[{1}]'".format(tag, tags)14301431 results = self.postgres.query_fetch_all(sql_str)14321433 return results14341435 def select_random_questions(self, questions, number_to_draw, question_type):1436 """ Return Questions by type """14371438 questionnaires = []14391440 number_to_draw = int(number_to_draw)1441 if not number_to_draw:1442 number_to_draw = 1014431444 limit = math.floor(number_to_draw / len(question_type))14451446 for qtype in question_type:1447 qlist = [question['question_id'] for question in questions \1448 if question['question_type'] == qtype]14491450 # SHUFFLE QUESTIONS1451 random.shuffle(qlist)14521453 qlist = qlist[:limit]1454 questionnaires += qlist14551456 if len(questionnaires) != number_to_draw:14571458 draw_again = number_to_draw - len(questionnaires)1459 qlist = [question['question_id'] for question in questions \1460 if question['question_type'] in question_type \1461 and question['question_id'] not in questionnaires]14621463 # SHUFFLE QUESTIONS1464 random.shuffle(qlist)14651466 qlist = qlist[:draw_again]1467 questionnaires += qlist14681469 return questionnaires14701471 def get_question_by_id(self, question_id):1472 """ Return Question Data by ID """14731474 sql_str = "SELECT * FROM questions WHERE question_id = '{0}'".format(question_id)1475 result = self.postgres.query_fetch_one(sql_str)14761477 return result14781479 def use_course(self, course_id):1480 """ CHECK IF COURSE IN USE """14811482 sql_str = "SELECT * FROM student_course WHERE"1483 sql_str += " course_id='{0}'".format(course_id)14841485 if not self.postgres.query_fetch_one(sql_str):14861487 return 114881489 return 014901491 def update_course(self, data, course_id=None):1492 """ UPDATE COURSE """14931494 updated_data = {}1495 updated_data['course_name'] = data['Course Name']1496 updated_data['description'] = data['Course Description']1497 updated_data['difficulty_level'] = data['Course Difficulty Level']1498 updated_data['requirements'] = data['Course Requirements']14991500 # INIT CONDITION1501 conditions = []15021503 # CONDITION FOR QUERY1504 conditions.append({1505 "col": "course_id",1506 "con": "=",1507 "val": data['Course ID']1508 })15091510 self.postgres.update('course', updated_data, conditions)15111512 return data['Course ID']15131514 def get_question_id(self, row):1515 """ RETURN QUESTION ID """15161517 if row['Question'] and row['Question ID']:15181519 return row['Question ID']15201521 sql_str = "SELECT question_id FROM questions WHERE"1522 sql_str += " question='{0}'".format(row['Question'])1523 sql_str += " AND question_type='{0}'".format(row['Question Type'])1524 sql_str += " AND tags='{0}'".format(row['Question Tags'])1525 response = self.postgres.query_fetch_one(sql_str)15261527 question_id = ""15281529 if not response:15301531 qtype = row['Question Type']15321533 question_id = self.sha_security.generate_token(False)15341535 temp = {}1536 temp['question_id'] = question_id1537 temp['question_type'] = row['Question Type']1538 temp['tags'] = json.dumps(row['Question Tags'].replace("\'", "").replace("\"", "")[1:-1].split(", "))1539 temp['shuffle_options'] = ""1540 temp['shuffle_answers'] = ""1541 temp['feedback'] = ""1542 array_choice = []15431544 if qtype == 'FITBT':15451546 ans = "".join(re.findall(r'[^\{$\}]', row['Question Correct Answer']))1547 answer = {}1548 answer['answer'] = row['Question'].replace("<ans>", str(ans))15491550 quest = {}1551 quest['question'] = row['Question']15521553 temp['correct_answer'] = json.dumps(answer)1554 temp['question'] = json.dumps(quest)15551556 elif qtype == 'FITBD':15571558 answer = {}1559 answer['answer'] = row['Question']15601561 allans = "".join(re.findall(r'[^\{$\}]', row['Question Correct Answer'])).split(", ")15621563 for ans in allans:15641565 correct_answer = answer['answer'].replace("[blank]", ans, 1)1566 answer['answer'] = correct_answer15671568 quest = {}1569 quest['question'] = row['Question'].replace("[blank]", "<ans>")15701571 temp['correct_answer'] = json.dumps(answer)1572 temp['question'] = json.dumps(quest)15731574 elif qtype == 'MULCH':15751576 choices = "".join(re.findall(r'[^\{$\}]', row['Question Choices']))1577 choices = choices.split(", ")15781579 for choice in choices:15801581 array_choice.append(choice)15821583 answer = {}1584 answer['answer'] = row['Question Correct Answer']15851586 quest = {}1587 quest['question'] = row['Question']15881589 temp['correct_answer'] = json.dumps(answer)1590 temp['question'] = json.dumps(quest)15911592 elif qtype == 'MATCH':15931594 temp['shuffle_options'] = row['Question Shuffle Options']1595 temp['shuffle_answers'] = row['Question Shuffle Answers']15961597 allans = "".join(re.findall(r'[^\{$\}]', row['Question Correct Answer'])).split(", ")1598 answer = {}1599 answer['answer'] = allans16001601 quest_data = row['Question'].replace("\"", "")1602 allquest = "".join(re.findall(r'[^\{$\}]', quest_data)).split(", ")1603 quest = {}1604 quest['question'] = allquest16051606 array_choice = "".join(re.findall(r'[^\{$\}]', row['Question Choices']))1607 array_choice = array_choice.split(", ")1608 temp['correct_answer'] = json.dumps(answer)1609 temp['question'] = json.dumps(quest)16101611 elif qtype == 'MULRE':16121613 temp['shuffle_options'] = row['Question Shuffle Options']1614 temp['shuffle_answers'] = row['Question Shuffle Answers']16151616 allans = row['Question Correct Answer'].replace("\"", "")1617 allans = "".join(re.findall(r'[^\{$\}]', allans)).split(", ")1618 answer = {}1619 answer['answer'] = allans16201621 quest = {}1622 quest['question'] = row['Question']16231624 array_choice = row['Question Choices'].replace("\"", "")1625 array_choice = "".join(re.findall(r'[^\{$\}]', array_choice))1626 array_choice = array_choice.split(", ")1627 temp['correct_answer'] = json.dumps(answer)1628 temp['question'] = json.dumps(quest)16291630 if row['Question Description']:16311632 temp['description'] = row['Question Description']16331634 else:1635 temp['description'] = "Lorem ipsum dolor sit amet, consectetur "1636 temp['description'] += "adipiscing elit, sed do eiusmod tempor "1637 temp['description'] += "incididunt ut labore et dolore magna aliqua."16381639 temp['choices'] = json.dumps(array_choice)1640 temp['correct'] = row['Question Correct']1641 temp['incorrect'] = row['Question Incorrect']1642 temp['num_eval'] = row['Question Num Eval'].upper() == 'TRUE'16431644 if row['Question Feedback']:1645 temp['feedback'] = row['Question Feedback']1646 temp['status'] = True1647 temp['created_on'] = time.time()1648 self.postgres.insert('questions', temp)16491650 else:16511652 question_id = response['question_id']16531654 return question_id165516561657 def get_period(self, epoch_range, format_range):1658 """ Return Start and End Time """16591660 start = epoch_range[0]1661 end = epoch_range[-1]16621663 year = datetime.fromtimestamp(int(end)).strftime('%Y')1664 month = datetime.fromtimestamp(int(end)).strftime('%m')1665 day = datetime.fromtimestamp(int(end)).strftime('%d')16661667 if format_range in ['day', 'days']:1668 end = datetime(int(year), int(month), int(day), 23, 59, 59).timestamp()16691670 elif format_range in ['weeks', 'week']:1671 end = self.week_end_date(end)16721673 elif format_range in ['year', 'years']:1674 month_end = calendar.monthrange(int(year), int(month))[1]1675 end = datetime(int(year), 12, int(month_end), 23, 59, 59).timestamp()16761677 else:1678 month_end = calendar.monthrange(int(year), int(month))[1]1679 end = datetime(int(year), int(month), int(month_end), 23, 59, 59).timestamp()16801681 tmp = {}1682 tmp['start'] = int(start)1683 tmp['end'] = int(end)16841685 return tmp16861687 def epoch_range(self, epoch_format, number):1688 """ Return Epoch Timestamp Coverage """16891690 if epoch_format in ['years', 'year']:1691 epoch_format = "years"16921693 if epoch_format in ['months', 'month']:1694 epoch_format = "months"16951696 if epoch_format in ['weeks', 'week']:1697 epoch_format = "weeks"16981699 if epoch_format in ['days', 'day']:1700 epoch_format = "days"17011702 year = datetime.now().strftime("%Y")1703 month = datetime.now().strftime("%m")1704 day = datetime.now().strftime("%d")17051706 is_default = False1707 if not epoch_format and not number:1708 start = datetime(int(year), 1, 1, 0, 0)1709 end = datetime(int(year), int(month), 1, 0, 0)1710 number = dateutil.relativedelta.relativedelta(end, start).months1711 epoch_format = "months"1712 is_default = True17131714 epoch = []17151716 if epoch_format == "months":1717 day = 117181719 if epoch_format == "years":1720 day = 11721 month = 117221723 base_start = datetime(int(year), int(month), int(day), 0, 0)17241725 if number and int(number):1726 for num in range(int(number)):1727 kwargs = {}1728 kwargs[epoch_format] = int(num + 1)17291730 start = base_start - dateutil.relativedelta.relativedelta(**kwargs)1731 epoch_start = round(start.timestamp())1732 epoch.append(epoch_start)17331734 if is_default:1735 epoch.append(round(base_start.timestamp()))1736 else:1737 epoch.append(round(base_start.timestamp()))1738 epoch.sort()1739 epoch.remove(epoch[0])17401741 epoch.sort()17421743 return epoch17441745 def week_end_date(self, epoch):1746 """ Return end of week date """17471748 timestamp = epoch1749 one_day = 864001750 end_week_date = (timestamp + (one_day * 7)) - 11751 return end_week_date17521753 def week_start_end(self, epoch):1754 """ Return week start and end """17551756 date = datetime.fromtimestamp(int(epoch)).strftime('%Y-%m-%d')17571758 date = datetime.strptime(date, '%Y-%m-%d')17591760 week_start = date - timedelta(days=date.weekday()) # Monday1761 week_end = week_start + timedelta(days=6) # Sunday17621763 data = {}1764 data['week_start'] = week_start.timestamp()1765 data['week_end'] = week_end.timestamp()1766 return data17671768 def epoch_week_number(self, epoch):1769 """ Return Week Number """17701771 return datetime.fromtimestamp(int(epoch)).strftime("%V")17721773 def yearend_month_date(self, epoch_date):1774 """ Return Month Year End Date in Epoch"""17751776 year = datetime.fromtimestamp(int(epoch_date)).strftime('%Y')1777 epoch_year = datetime(int(year), 12, 1, 0, 0).strftime('%s')1778 return epoch_year17791780 def month_end(self, epoch_date):1781 """ Return Month End """17821783 year = datetime.fromtimestamp(int(epoch_date)).strftime('%Y')1784 month = datetime.fromtimestamp(int(epoch_date)).strftime('%m')1785 day = calendar.monthrange(int(year), int(month))[1]17861787 month_end = int(datetime(int(year), int(month), int(day), 0, 0).timestamp())1788 return month_end17891790 def get_epoch_weekday(self, epoch_date):1791 """ Return day of epoch date """17921793 return datetime.fromtimestamp(epoch_date).strftime("%A")17941795 def get_epoch_month(self, epoch_date):1796 """ Return Epoch Date Month """17971798 return datetime.fromtimestamp(int(epoch_date)).strftime('%b')17991800 def get_epoch_year(self, epoch_date):1801 """ Return Epoch Year """18021803 return datetime.fromtimestamp(int(epoch_date)).strftime('%Y')18041805 def day_end(self, epoch_date):1806 """ Return Day End"""18071808 # END1809 year = datetime.fromtimestamp(int(epoch_date)).strftime("%Y")1810 month = datetime.fromtimestamp(int(epoch_date)).strftime("%m")1811 day = datetime.fromtimestamp(int(epoch_date)).strftime("%d")1812 end = int(datetime(int(year), int(month), int(day), 23, 59, 59).timestamp())1813 return end18141815 def generate_random_questions(self, question_types, number_to_draw, tags):1816 """ Generate Random Question """18171818 questions = []1819 limit = math.floor(number_to_draw / len(question_types))1820 for qtype in question_types:18211822 questions += self.get_random_questions(qtype, limit, tags)18231824 if len(questions) != number_to_draw:18251826 draw_again = number_to_draw - len(questions)1827 question_type = random.choice(question_types)1828 questions += self.get_random_questions(question_type, draw_again, tags)18291830 return questions1831 1832 def get_random_questions(self, question_type, number_to_draw, tags):1833 """ Return Question by Type and Tags """18341835 if question_type.upper() == "MATCH":1836 # GENERATE FITBT MATCHING TYPE QUESTIONS1837 questions = self.create_match_question(tags, number_to_draw)18381839 else:1840 questionnaires = self.get_questions(question_type, tags, number_to_draw)1841 questions = [question['question_id'] for question in questionnaires]18421843 return questions18441845 def get_questions(self, question_type, tags, limit):1846 """ Return Questions """18471848 tag = '"tags"'18491850 sql_str = "SELECT * FROM questions WHERE question_type='{0}'".format(question_type)1851 if tags:1852 tags = ', '.join('"{0}"'.format(tag) for tag in tags)1853 sql_str += " AND CAST({0} AS text) = '[{1}]'".format(tag, tags)18541855 results = self.postgres.query_fetch_all(sql_str)18561857 if results:1858 # questions = [result['question_id'] for result in results]1859 random.shuffle(results)1860 results = results[:limit]1861 return results18621863 def create_match_question(self, tags, number_to_draw):1864 """ Create Matching Type Questions """18651866 data = []1867 match_qlimit = 51868 for _ in range(number_to_draw):1869 questions = self.get_questions("FITBT", tags, match_qlimit)18701871 if questions:1872 match_questions = []1873 correct_answer = []1874 for question in questions:18751876 quest = question['question']['question'].replace("<ans>", "")1877 if "rest" in question['question']['question']:1878 quest = question['question']['question'].replace("<ans> rest <ans>", "")18791880 answer = question['correct_answer']['answer'].replace(quest, "")1881 if "rest" in answer:1882 answer = answer.replace("rest", "/")1883 answer = answer.replace(" ", "")18841885 match_questions.append(quest.rstrip())1886 correct_answer.append(answer)18871888 choices = correct_answer1889 random.shuffle(choices)18901891 tmp_question = {}1892 tmp_question['question'] = match_questions18931894 tmp_correct_answer = {}1895 tmp_correct_answer['answer'] = correct_answer18961897 temp = {}1898 temp['question_id'] = self.sha_security.generate_token(False)1899 temp['question'] = json.dumps(tmp_question)1900 temp['question_type'] = "MATCH"1901 temp['tags'] = json.dumps(tags)1902 temp['choices'] = json.dumps(choices)1903 temp['shuffle_options'] = True1904 temp['shuffle_answers'] = False1905 temp['num_eval'] = True1906 temp['correct_answer'] = json.dumps(tmp_correct_answer)1907 temp['correct'] = questions[0]['correct']1908 temp['incorrect'] = questions[0]['incorrect']1909 temp['feedback'] = questions[0]['feedback']1910 temp['description'] = questions[0]['description']1911 temp['status'] = True1912 temp['created_on'] = time.time()19131914 question_id = self.postgres.insert('questions', temp, 'question_id')1915 data.append(question_id)19161917 return data19181919 def get_translation(self, message, language):1920 """ Return Translation """19211922 sql_str = "SELECT translation FROM translations WHERE word_id=("1923 sql_str += "SELECT word_id FROM words WHERE"1924 sql_str += " name = '{0}') AND ".format(message)1925 sql_str += "language_id=(SELECT language_id FROM language WHERE "1926 sql_str += "initial='{0}')".format(language)19271928 return self.postgres.query_fetch_one(sql_str)19291930 def update_translate(self, data, userid):1931 """ Update Translation """19321933 sql_str = "SELECT language FROM account WHERE"1934 sql_str += " id='{0}'".format(userid)1935 language = self.postgres.query_fetch_one(sql_str)19361937 if language['language'] != 'en-US':1938 keys = ['rows', 'data', 'course']1939 for key in keys:19401941 if key in data.keys():19421943 if type(data[key]) == list:1944 for row in data[key]:19451946 # COURSE NAME1947 if 'course_name' in row.keys():1948 row['course_name'] = self.translate_key(language,1949 row['course_name'])19501951 # DESCRIPTION1952 if 'description' in row.keys():1953 row['description'] = self.translate_key(language,1954 row['description'])19551956 if 'notification_name' in row.keys():1957 row['notification_name'] = self.translate_key(language,1958 row['notification_name'])1959 else:1960 if 'course_name' in data[key].keys():1961 if type(data[key]['course_name']) == str:19621963 data[key]['course_name'] = self.translate_key(language,1964 data[key]['course_name'])19651966 if 'description' in data[key].keys():1967 if type(data[key]['description']) == str:19681969 data[key]['description'] = self.translate_key(language,1970 data[key]['description'])19711972 # else:19731974 # if 'course_name' in data[key].keys():1975 # if type(data[key]['course_name']) == str:19761977 # data[key]['course_name'] = self.translate_key(language,1978 # data[key]['course_name'])1979 # else:1980 # for row in data[key]:1981 # if 'course_name' in row.keys():1982 # row['course_name'] = self.translate_key(language,1983 # row['çourse_name'])1984 1985 # # DESCRIPTION1986 # if 'description' in data[key].keys():19871988 # if type(data[key]['description']) == str:1989 1990 # data[key]['description'] = self.translate_key(language,1991 # data[key]['course_name'])1992 # else:1993 # for row in data[key]:1994 # if 'course_name' in row.keys():1995 # row['course_name'] = self.translate_key(language, row['description'])19961997 return data19981999 def translate_key(self, language, original):2000 """ Translate Key """20012002 message = "".join(re.findall(r'[a-zA-Z\ \.\,]', original))2003 translate = self.get_translation(message, language['language'])20042005 if translate:2006 return translate['translation']20072008 return original20092010 def get_account_details(self, user_id):2011 """ Return Account Details """20122013 sql_str = "SELECT * FROM account WHERE id='{0}'".format(user_id)2014 result = self.postgres.query_fetch_one(sql_str)
...
progress.py
Source:progress.py
...23 exercise_table = "{0}_exercise".format(key)24 sql_str = "SELECT * FROM {0}".format(exercise_table)25 sql_str += " WHERE exercise_id='{0}'".format(exercise_id)26 sql_str += " AND account_id='{0}' AND status is True".format(user_id)27 result = self.postgres.query_fetch_one(sql_str)2829 if result:3031 # QUESTIONS32 column_id = "{0}_exercise_id".format(key)3334 sql_str = "SELECT * FROM {0}_exercise_questions".format(key)35 sql_str += " WHERE {0} = '{1}'".format(column_id, result[column_id])36 questions = self.postgres.query_fetch_all(sql_str)3738 score = 039 for question in questions:40 ans = self.check_answer(question['course_question_id'], question['answer'])4142 if ans['isCorrect'] is True:43 score += 14445 # UPDATE PROGRESS46 progress = self.check_progress(questions)4748 # PERCENT SCORE49 total = len(questions)50 percent_score = self.format_progress((score / total) * 100)5152 # UPDATE SCORE53 tmp = {}54 tmp['score'] = score55 tmp['progress'] = progress56 tmp['percent_score'] = percent_score57 if key.upper() == "STUDENT":58 tmp['end_on'] = time.time()5960 tmp['update_on'] = time.time()61 conditions = []6263 conditions.append({64 "col": "exercise_id",65 "con": "=",66 "val": exercise_id67 })6869 conditions.append({70 "col": column_id,71 "con": "=",72 "val": result[column_id]73 })7475 data = self.remove_key(tmp, "exercise_id")7677 self.postgres.update(exercise_table, data, conditions)7879 def update_subsection_progress(self, user_id, exercise_id, key):80 """ Update Course Progress """8182 exercise_table = "{0}_exercise".format(key)83 subsection_table = "{0}_subsection".format(key)84 exercise_questions_table = "{0}_exercise_questions".format(key)85 key_subsection_id = "{0}_subsection_id".format(key)86 key_exercise_id = "{0}_exercise_id".format(key)8788 sql_str = "SELECT * FROM exercise e LEFT JOIN {0}".format(subsection_table)89 sql_str += " sub ON e.subsection_id = sub.subsection_id"90 sql_str += " WHERE e.exercise_id='{0}'".format(exercise_id)91 subsection = self.postgres.query_fetch_one(sql_str)9293 student_subsection_id = subsection[key_subsection_id]94 subsection_id = subsection['subsection_id']95 course_id = subsection['course_id']9697 sql_str = "SELECT answer, percent_score FROM {0}".format(exercise_questions_table)98 sql_str += " WHERE {0} IN (SELECT {0}".format(key_exercise_id)99 sql_str += " FROM {0} WHERE status is True AND".format(exercise_table)100 sql_str += " account_id='{0}' AND".format(user_id)101 sql_str += " exercise_id IN (SELECT exercise_id FROM exercise WHERE "102 sql_str += " subsection_id='{0}' AND status is True))".format(subsection_id)103 student_exercise = self.postgres.query_fetch_all(sql_str)104105 answer = [dta['answer'] for dta in student_exercise]106 total = len(answer)107 not_answer = [None, '', []]108 total_answer = len([ans for ans in answer if ans not in not_answer])109 # print("Total: {0} Answer: {1}".format(total, total_answer))110 progress = 0111 if total_answer:112 progress = self.format_progress((total_answer / total) * 100)113114 # PERCENT SCORE115 percent_score = [dta['percent_score'] for dta in student_exercise]116 total = len(percent_score)117 percent_100 = len([dta['percent_score'] for dta in student_exercise \118 if dta['percent_score'] is not None and \119 int(dta['percent_score']) == 100])120121 percent_score = self.format_progress((percent_100 / total) * 100)122123 # UPDATE PROGRESS124 conditions = []125126 conditions.append({127 "col": key_subsection_id,128 "con": "=",129 "val": student_subsection_id130 })131132 conditions.append({133 "col": "course_id",134 "con": "=",135 "val": course_id136 })137138 data = {}139 data['progress'] = progress140 data['percent_score'] = percent_score141 data['update_on'] = time.time()142143 self.postgres.update(subsection_table, data, conditions)144145 def update_section_progress(self, user_id, exercise_id, key):146 """ Update Course Progress """147148 section_table = "{0}_section".format(key)149 key_section_id = "{0}_section_id".format(key)150 exercise_question_table = "{0}_exercise_questions".format(key)151 key_exercise_id = "{0}_exercise_id".format(key)152 exercise_table = "{0}_exercise".format(key)153154 sql_str = "SELECT * FROM exercise e"155 sql_str += " LEFT JOIN {0} ss ON e.section_id = ss.section_id".format(section_table)156 sql_str += " WHERE e.exercise_id='{0}'".format(exercise_id)157 section = self.postgres.query_fetch_one(sql_str)158159 section_id = section['section_id']160 course_id = section['course_id']161 student_section_id = section[key_section_id]162163 sql_str = "SELECT answer, percent_score FROM {0}".format(exercise_question_table)164 sql_str += " WHERE {0} IN (SELECT {0}".format(key_exercise_id)165 sql_str += " FROM {0} WHERE status is True AND".format(exercise_table)166 sql_str += " account_id='{0}' AND".format(user_id)167 sql_str += " exercise_id IN (SELECT exercise_id FROM exercise WHERE "168 sql_str += " section_id='{0}' AND status is True))".format(section_id)169 student_exercise = self.postgres.query_fetch_all(sql_str)170171 answer = [dta['answer'] for dta in student_exercise]172 total = len(answer)173 not_answer = [None, '', []]174 total_answer = len([ans for ans in answer if ans not in not_answer])175176 progress = 0177 if total_answer:178 progress = self.format_progress((total_answer / total) * 100)179180 # PERCENT SCORE181 percent_100 = len([dta['percent_score'] for dta in student_exercise \182 if dta['percent_score'] is not None and \183 int(dta['percent_score']) == 100])184185 percent_score = self.format_progress((percent_100 / total) * 100)186187 # UPDATE PROGRESS188 conditions = []189190 conditions.append({191 "col": key_section_id,192 "con": "=",193 "val": student_section_id194 })195196 conditions.append({197 "col": "course_id",198 "con": "=",199 "val": course_id200 })201202 data = {}203 data['progress'] = progress204 data['percent_score'] = percent_score205 data['update_on'] = time.time()206207 self.postgres.update(section_table, data, conditions)208209210 def update_course_progress(self, user_id, exercise_id, key):211 """ Update Course Progress """212213 exercise_table = "{0}_exercise".format(key)214 exercise_question_table = "{0}_exercise_questions".format(key)215 key_exercise_id = "{0}_exercise_id".format(key)216 course_table = "{0}_course".format(key)217218 sql_str = "SELECT * FROM {0} WHERE".format(exercise_table)219 sql_str += " exercise_id='{0}' AND status=true".format(exercise_id)220 sql_str += " AND account_id='{0}'".format(user_id)221 student_course = self.postgres.query_fetch_one(sql_str)222 course_id = student_course['course_id']223224 sql_str = "SELECT answer, percent_score FROM {0}".format(exercise_question_table)225 sql_str += " WHERE {0} IN (SELECT {0}".format(key_exercise_id)226 sql_str += " FROM {0} WHERE status is True AND".format(exercise_table)227 sql_str += " account_id='{0}' AND status is True)".format(user_id)228 student_exercise = self.postgres.query_fetch_all(sql_str)229230 answer = [dta['answer'] for dta in student_exercise]231 total = len(answer)232233 not_answer = [None, '', []]234 total_answer = len([ans for ans in answer if ans not in not_answer])235236 progress = self.format_progress((total_answer / total) * 100)237238 # PERCENT SCORE239 percent_score = [dta['percent_score'] for dta in student_exercise]240 total = len(percent_score)241 percent_100 = len([dta['percent_score'] for dta in student_exercise \242 if dta['percent_score'] is not None and \243 int(dta['percent_score']) == 100])244245 percent_score = self.format_progress((percent_100 / total) * 100)246247 # UPDATE PROGRESS248 conditions = []249250 conditions.append({251 "col": "account_id",252 "con": "=",253 "val": user_id254 })255256 conditions.append({257 "col": "course_id",258 "con": "=",259 "val": course_id260 })261262 data = {}263 data['progress'] = progress264 data['percent_score'] = percent_score265 data['update_on'] = time.time()266267 self.postgres.update(course_table, data, conditions)268269 if key == 'student':270271 self.all_progress(user_id)272 self.group_progress(user_id)273274 def all_progress(self, user_id):275 """ UPDATE ALL PROGRESS """276277 sql_str = "SELECT progress FROM student_course WHERE"278 sql_str += " account_id='{0}' AND status='t'".format(user_id)279 progress = self.postgres.query_fetch_all(sql_str)280281 total_prog = 0282 total_course = len(progress) * 100283 for pgrss in progress:284285 total_prog = total_prog + float(pgrss['progress'])286287 average = self.format_progress((total_prog/total_course) * 100)288289 # UPDATE PROGRESS290 conditions = []291292 conditions.append({293 "col": "id",294 "con": "=",295 "val": user_id296 })297298 data = {}299 data['progress'] = average300 data['update_on'] = time.time()301302 self.postgres.update('account', data, conditions)303304 return 1305306 def group_progress(self, user_id):307 """ UPDATE GROUP PROGRESS """308309 sql_str = "SELECT user_group_id FROM user_group_students WHERE"310 sql_str += " student_id='{0}'".format(user_id)311312 user_group = self.postgres.query_fetch_all(sql_str)313314 # UPDATE GROUP315 for sgroup in user_group:316317 user_group_id = sgroup['user_group_id']318319 # GET ALL USER PROGRESS IN A GROUP320 sql_str = "SELECT progress FROM account WHERE id IN ("321 sql_str += "SELECT student_id FROM user_group_students WHERE"322 sql_str += " user_group_id='{0}')".format(user_group_id)323 progress = self.postgres.query_fetch_all(sql_str)324325 total_prog = 0326 total_student = len(progress) * 100327328 for pgrss in progress:329330 total_prog = total_prog + float(pgrss['progress'])331332 # GET AVERAGE PROGRESS333 average = self.format_progress((total_prog/total_student) * 100)334335 # UPDATE PROGRESS336 conditions = []337338 conditions.append({339 "col": "user_group_id",340 "con": "=",341 "val": user_group_id342 })343344 # GET LEAST PERFORMER345 sql_str = "SELECT id, ROUND(cast(progress as numeric),2) AS progress"346 sql_str += " FROM account WHERE id IN (SELECT student_id FROM"347 sql_str += " user_group_students WHERE"348 sql_str += " user_group_id='{0}')".format(user_group_id)349 sql_str += " ORDER BY progress ASC"350 student = self.postgres.query_fetch_one(sql_str)351352 # UPDATE GROUP PROGRESS353 data = {}354 data['least_performer'] = student['id']355 data['progress'] = average356 data['update_on'] = time.time()357358 self.postgres.update('user_group', data, conditions)359
...
questions.py
Source:questions.py
...23 """ Generate Questionnaires based on settings """2425 sql_str = "SELECT * FROM exercise WHERE exercise_id = '{0}'".format(exercise_id)26 sql_str += " AND course_id = '{0}'".format(course_id)27 result = self.postgres.query_fetch_one(sql_str)2829 if result:3031 # shuffle = result['shuffled']32 # question_types = result['question_types']33 # tags = result['tags']34 # cast = '"tags"'3536 # qtype = ""37 # if question_types:38 # qtype = ','.join("'{0}'".format(qtype) for qtype in question_types)3940 sql_str = "SELECT * FROM course_question"41 sql_str += " WHERE course_id = '{0}'".format(course_id)42 sql_str += " AND exercise_id='{0}'".format(result['exercise_id'])4344 # if shuffle is True:45 # if question_types:46 # sql_str += " AND question_type IN ({0})".format(qtype)4748 # if tags not in [None, [], str(['']), str([""]), ['']]:49 # sql_str += " AND CAST({0} AS text) = '{1}'".format(cast, json.dumps(tags))5051 questions = self.postgres.query_fetch_all(sql_str)5253 number_to_draw = 10 # BY DEFAULT54 if result['number_to_draw']:55 number_to_draw = result['number_to_draw']5657 # questions = self.select_questions(questions, number_to_draw, question_types, shuffle)58 questions = [question['course_question_id'] for question in questions]5960 questions = questions[:number_to_draw]61 result['questions'] = questions6263 self.add_student_exercise(user_id, course_id, key, result)64 return result6566 def select_questions(self, questions, number_to_draw, question_type, shuffle):67 """ Return Questions by type """6869 questionnaires = []7071 if not question_type:72 question_type = ['FITBT', 'MULRE', 'MATCH', 'MULCH']73 limit = math.floor(number_to_draw / len(question_type))7475 for qtype in question_type:76 qlist = [question['course_question_id'] for question in questions \77 if question['question_type'] == qtype]7879 if shuffle is True:80 # SHUFFLE QUESTIONS81 random.shuffle(qlist)8283 qlist = qlist[:limit]84 questionnaires += qlist8586 if len(questionnaires) != number_to_draw:8788 draw_again = number_to_draw - len(questionnaires)89 qlist = [question['course_question_id'] for question in questions \90 if question['question_type'] in question_type \91 and question['course_question_id'] not in questionnaires]9293 if shuffle is True:94 # SHUFFLE QUESTIONS95 random.shuffle(qlist)9697 qlist = qlist[:draw_again]98 questionnaires += qlist99100 return questionnaires101102 def regenerate_questions(self, exercise_id, user_id, key):103 """ Generate Seed Questionnaires based on settings """104105 sql_str = "SELECT * FROM exercise WHERE exercise_id = '{0}'".format(exercise_id)106 result = self.postgres.query_fetch_one(sql_str)107 shuffle = result['shuffled']108 question_types = result['question_types']109 tags = result['tags']110 cast = '"tags"'111112 exercise_table = "{0}_exercise".format(key)113 questions_table = "{0}_exercise_questions".format(key)114 key_id = "{0}_exercise_id".format(key)115116 sql_str = "SELECT * FROM {0} se LEFT JOIN {1}".format(exercise_table, questions_table)117 sql_str += " seq ON se.{0} = seq.{0}".format(key_id)118 sql_str += " WHERE se.status is True AND se.exercise_id = '{0}'".format(exercise_id)119 result = self.postgres.query_fetch_all(sql_str)120121 answered = [res['course_question_id'] for res in result if res['answer'] is not None]122 total_answered = len(answered)123 total = len(result)124 number_to_draw = total - total_answered125126 qtype = ""127 if question_types:128 qtype = ','.join("'{0}'".format(qtype) for qtype in question_types)129130 sql_str = "SELECT * FROM course_question"131 sql_str += " WHERE exercise_id='{0}'".format(result[0]['exercise_id'])132 if question_types:133 sql_str += " AND question_type IN ({0})".format(qtype)134135 if answered:136 answered_questions = ','.join("'{0}'".format(ans) for ans in answered)137 sql_str += " AND course_question_id NOT IN ({0})".format(answered_questions)138139 if tags:140 tags = ', '.join('"{0}"'.format(tag) for tag in tags)141 sql_str += " AND CAST({0} AS text) = '[{1}]'".format(cast, tags)142143 questions = self.postgres.query_fetch_all(sql_str)144 questions = self.select_questions(questions, number_to_draw, question_types, shuffle)145146 # DELETE ITEMS TO SHUFFLE NEW QUESTION(S)147 no_answer = [res['course_question_id'] for res in result if res['answer'] is None]148 self.delete_item_sequence(key, result[0][key_id], no_answer)149150 # ADD STUDENT EXERCISE QUESTIONS151 next_item = self.get_next_sequence(result[0][key_id], key)152 if self.add_student_questions(result[0][key_id], key, questions,153 next_item, user_id):154 return 1155 return 0156157 def delete_item_sequence(self, key, student_exercise_id, items):158 """ DELETE ITEMS TO BE SHUFFLED """159160 key_exercise_id = "{0}_exercise_id".format(key)161 table = "{0}_exercise_questions".format(key)162163 conditions = []164165 conditions.append({166 "col": "course_question_id",167 "con": "in",168 "val": items169 })170171 conditions.append({172 "col": key_exercise_id,173 "con": "=",174 "val": student_exercise_id175 })176177 if self.postgres.delete(table, conditions):178 return 1179180 return 0181182 def get_next_sequence(self, student_exercise_id, key):183 """ Return next item sequence """184185 table = "{0}_exercise_questions".format(key)186 key_id = "{0}_exercise_id".format(key)187188 sql_str = "SELECT MAX(sequence) as sequence FROM {0}".format(table)189 sql_str += " WHERE {0}='{1}'".format(key_id, student_exercise_id)190 result = self.postgres.query_fetch_one(sql_str)191192 if result['sequence'] is None:193 return 1194195 return result['sequence'] + 1196197 def add_student_exercise(self, user_id, course_id, key, data):198 """ Assign Exercise to Student """199200 if data:201202 key_exercise_id = "{0}_exercise_id".format(key)203 table = "{0}_exercise".format(key)204 # ADD EXERCISE205206 temp = {}207 temp[key_exercise_id] = self.sha_security.generate_token(False)208 temp['exercise_id'] = data['exercise_id']209 temp['account_id'] = user_id210 temp['course_id'] = course_id211 temp['exercise_number'] = data['exercise_number']212 temp['status'] = True213 temp['created_on'] = time.time()214215 add = self.postgres.insert(table, temp, key_exercise_id)216217 # ADD QUESTIONS218 sequence = 1219 self.add_student_questions(add, key, data['questions'], sequence, user_id)220221 return 1222223 return 0224225 def add_student_questions(self, exercise_id, key, questions, sequence, user_id):226 """ ADD STUDENT EXERCISE QUESTIONS BY SEED """227228 key_exercise_id = "{0}_exercise_id".format(key)229 table = "{0}_exercise_questions".format(key)230231 # ADD QUESTIONS232 for question in questions:233234 tmp = {}235 tmp[key_exercise_id] = exercise_id236 tmp['account_id'] = user_id237 tmp['course_question_id'] = question238 tmp['sequence'] = sequence239 tmp['skip_times'] = 0240241 self.postgres.insert(table, tmp, key_exercise_id)242 sequence += 1243244 return 1245246 # FOR COURSE DEVELOPMENT247 def get_question_by_id(self, question_id):248 """ Return Question Data by ID """249250 sql_str = "SELECT * FROM questions WHERE question_id = '{0}'".format(question_id)251 result = self.postgres.query_fetch_one(sql_str)252253 return result254255 def get_questions_by_condition(self, question_types, tags):256 """ Return Question by type and tags """257258 qtype = ','.join("'{0}'".format(qtype) for qtype in question_types)259 tag = '"tags"'260261 sql_str = "SELECT * FROM questions WHERE question_type IN ({0})".format(qtype)262 if tags:263 tags = ', '.join('"{0}"'.format(tag) for tag in tags)264 sql_str += "AND CAST({0} AS text) = '[{1}]'".format(tag, tags)265
...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!