├── Procfile ├── .gitignore ├── requirements.txt ├── .idea ├── .gitignore ├── vcs.xml ├── misc.xml ├── inspectionProfiles │ └── profiles_settings.xml ├── modules.xml └── ASTU__COBOT.iml ├── Bot ├── __init__.py ├── utils.py ├── __main__.py ├── helpers │ ├── Database.py │ ├── BotStatus.py │ ├── exams.py │ ├── materials.py │ ├── ManageCourse.py │ ├── buttons.py │ ├── courses.py │ ├── strings.py │ ├── courses.json │ └── course_set.json ├── Admin │ └── __init__.py └── plugins │ ├── AdminHandler.py │ ├── MessageHandler.py │ ├── QuestionsHandler.py │ ├── InlineSearch.py │ ├── UserCallbackHandler.py │ └── StateHandler.py ├── config.py └── README.md /Procfile: -------------------------------------------------------------------------------- 1 | worker: python -m Bot -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .idea/ 3 | .env -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiogram~=2.25 2 | pyrebase4 3 | python-dotenv -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Bot/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from aiogram import Bot, Dispatcher 3 | from aiogram.contrib.fsm_storage.memory import MemoryStorage 4 | from config import API_TOKEN 5 | 6 | logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s', level=logging.INFO) 7 | 8 | bot = Bot(token=API_TOKEN) 9 | dp = Dispatcher(bot, storage=MemoryStorage()) 10 | -------------------------------------------------------------------------------- /.idea/ASTU__COBOT.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Bot/utils.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import logging 3 | import importlib 4 | from pathlib import Path 5 | 6 | 7 | def load_plugins(plugin_name): 8 | path = Path(f"Bot/plugins/{plugin_name}.py") 9 | name = "Bot.plugins.{}".format(plugin_name) 10 | spec = importlib.util.spec_from_file_location(name, path) 11 | load = importlib.util.module_from_spec(spec) 12 | load.logger = logging.getLogger(plugin_name) 13 | spec.loader.exec_module(load) 14 | sys.modules["Bot.plugins." + plugin_name] = load 15 | print("Bot has Started " + plugin_name) 16 | -------------------------------------------------------------------------------- /Bot/__main__.py: -------------------------------------------------------------------------------- 1 | import glob 2 | from pathlib import Path 3 | 4 | from aiogram.utils import executor 5 | 6 | from Bot.utils import load_plugins 7 | import logging 8 | from Bot import dp 9 | 10 | logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s', 11 | level=logging.INFO) 12 | 13 | path = "Bot/plugins/*.py" 14 | files = glob.glob(path) 15 | for name in files: 16 | with open(name) as a: 17 | patt = Path(a.name) 18 | plugin_name = patt.stem 19 | load_plugins(plugin_name.replace(".py", "")) 20 | 21 | print("Bot Started Successfully!") 22 | 23 | if __name__ == "__main__": 24 | executor.start_polling(dp) 25 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import pyrebase 2 | import os 3 | from dotenv import load_dotenv 4 | 5 | # loading env configs 6 | load_dotenv() 7 | 8 | API_TOKEN = os.getenv("API_TOKEN") 9 | admin_group_id = os.getenv("ADMIN_GROUP") 10 | 11 | firebaseConfig = { 12 | "apiKey": os.getenv('apiKey'), 13 | "authDomain": os.getenv('authDomain'), 14 | "databaseURL": os.getenv('databaseURL'), 15 | "projectId": os.getenv('projectId'), 16 | "storageBucket": os.getenv('storageBucket'), 17 | "messagingSenderId": os.getenv('messagingSenderId'), 18 | "appId": os.getenv('appId'), 19 | "measurementId": os.getenv('measurementId') 20 | } 21 | 22 | db = pyrebase.initialize_app(firebaseConfig).database() 23 | 24 | admins = db.get().val()["admins"] 25 | 26 | CourseFile = db.child("courses").get().val() 27 | -------------------------------------------------------------------------------- /Bot/helpers/Database.py: -------------------------------------------------------------------------------- 1 | from config import db 2 | 3 | 4 | class Users(object): 5 | def __init__(self): 6 | self.Users = "Users" 7 | 8 | def is_new(self, userid): 9 | """checking if user is new for the bot or not""" 10 | 11 | if db.child(self.Users).child(userid).get().val() is None: 12 | return True 13 | else: 14 | return False 15 | 16 | def add_user(self, userid, data): 17 | db.child(self.Users).child(userid).set(data) 18 | 19 | def set_user_language(self, userid, lang): 20 | db.child(self.Users).child(userid).update({"lang": lang}) 21 | 22 | def get_user_lang(self, userid): 23 | return db.child(self.Users).child(userid).get().val()["lang"] 24 | 25 | def get_total_users(self): 26 | return len(db.child(self.Users).get().val()) 27 | 28 | 29 | class CsFile: 30 | def __init__(self): 31 | self.course = "courses" 32 | 33 | def get(self): 34 | return db.child(self.course).get().val() 35 | 36 | 37 | class DptFile: 38 | def __init__(self): 39 | self.dpt = "dpt" 40 | 41 | def get(self): 42 | return db.child(self.dpt).get().val() 43 | -------------------------------------------------------------------------------- /Bot/helpers/BotStatus.py: -------------------------------------------------------------------------------- 1 | from Bot import bot 2 | mode = 'live' 3 | 4 | 5 | def status(): 6 | TEXT = f"Total Bot Users: " \ 7 | f"\nActive Users: " \ 8 | f"\nDead Users: " \ 9 | f"\nTotal Courses: " \ 10 | f"\nTotal Materials: " 11 | return TEXT 12 | 13 | 14 | async def log(event): 15 | TEXT = f"""-----------LOG----------- 16 | 🆔 {event.from_user.id} ( {event.from_user.first_name} ) 17 | 🤖 {event.from_user.is_bot} 18 | 👤 {event.from_user.first_name} 19 | ➡️ {event.from_user.last_name} 20 | 🌀 @{event.from_user.username} 21 | 22 | {event.text}""" 23 | if mode == 'test': 24 | print(TEXT) 25 | else: 26 | await bot.send_message(-1001972528530, TEXT, parse_mode="HTML") 27 | 28 | 29 | async def adminLog(event, stat): 30 | TEXT = f"""-----------ADMIN LOG----------- 31 | @Binitech 32 | 🆔 {event.from_user.id} ( {event.from_user.first_name} ) 33 | 🤖 {event.from_user.is_bot} 34 | 👤 {event.from_user.first_name} 35 | ➡️ {event.from_user.last_name} 36 | 🌀 @{event.from_user.username} 37 | State: {stat}""" 38 | if mode == 'test': 39 | print(TEXT) 40 | else: 41 | await bot.send_message(-1001972528530, TEXT, parse_mode="HTML") 42 | -------------------------------------------------------------------------------- /Bot/helpers/exams.py: -------------------------------------------------------------------------------- 1 | from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup 2 | 3 | from Bot import bot 4 | from Bot.helpers import strings 5 | from Bot.helpers.Database import CsFile 6 | 7 | 8 | def list_exams(code, start=0, end=10, i=1, lang=0): 9 | mats = CsFile().get()[code]['exams'] 10 | mat = mats[start:end] 11 | txt = [] 12 | btn = InlineKeyboardMarkup(row_width=5) 13 | for x in mat: 14 | txt.append( 15 | f"{str(i).zfill(2)} 🔗 {x[0]}" 16 | ) 17 | btn.insert(InlineKeyboardButton(f"{str(i).zfill(2)}", callback_data=f"displayExam_{code}_{i - 1}")) 18 | i += 1 19 | if start >= 10: 20 | btn.add(InlineKeyboardButton(strings.backBtnString[lang], 21 | callback_data=f"listExam_back_{start - 10}_{end - 10}_{i - 10 - len(mat)}_{code}")) 22 | if end < len(mats): 23 | btn.insert(InlineKeyboardButton(strings.nextBtnString[lang] 24 | , callback_data=f"listExam_next_{start + 10}_{end + 10}_{i}_{code}")) 25 | TEXT = "\n".join(txt) 26 | text = f'➖➖ 📝Previous Year Exams ➖➖\n\nName: {CsFile().get()[code]["name"]}' \ 27 | f'\n\n{TEXT}\n\n📚Find More from : @ASTU_COBOT' 28 | return text, btn 29 | 30 | 31 | async def display_exam(uid): 32 | ch = -1001655193585 33 | await bot.copy_message(uid, ch, 8) 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚡ ASTU Course outline Bot 😋 2 | 3 | - A Telegram Bot to provide course outline and material for university students. 4 | 5 | ## ⚡ Vars: 🔥 6 | 7 | * `API_TOKEN`: From BotFather 8 | * `FireBase Keys`: From Firebase settings 9 | 10 | 11 | ## ⚡ Bot Features: 🔥 12 | ### User Panel 13 | 1) Supports Amharic and English Language. 14 | 2) Searching courses on the Inline searching mode. 15 | 3) Categorizing and displaying course by collage, school, department, year and semester. 16 | 4) Providing course material and course details. 17 | 5) Showing how to use the bot on the Help Desk. 18 | 6) Providing Department and Ambulance phone number or contact for students. 19 | 20 | ### Admin Panel 21 | 1) Admin Management: adding and removing admins for the bot. 22 | 2) Course Manager: Editing Course Name, Course Description, Course Credit Hour, Course File. 23 | 3) Material Management: Adding and Removing Materials. 24 | 4) Bot Status: Total Bot Users Count, Dead Users Count, Total materials Counter, Total Courses Counter. 25 | ## Author 26 | 27 | 👤 **Tamirat Ayalew (вιηι)** 28 | 29 | - Telegram: [@BiniTech](https://t.me/BiniTech) 30 | - Twitter: [@TechBini](https://twitter.com/TechBini) 31 | - Github: [@BiniTech](https://github.com/binitech) 32 | 33 | ## 🤝 Contributing 34 | 35 | Contributions, issues and feature requests are welcome.
36 | Feel free to check [issues page](https://github.com/binitech/Course-outline-bot/issues) if you want to contribute.
37 | 38 | ## Show your support 39 | 40 | Please ⭐️ this repository if this project helped you! 41 | -------------------------------------------------------------------------------- /Bot/helpers/materials.py: -------------------------------------------------------------------------------- 1 | from Bot.helpers.Database import CsFile 2 | from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup 3 | from Bot.helpers import strings 4 | 5 | 6 | def materials(lang=0, start=0, end=10, i=1): 7 | courses = list(CsFile().get())[start:end] 8 | txt = [] 9 | btn = InlineKeyboardMarkup(row_width=5) 10 | for x in courses: 11 | txt.append( 12 | f"*{str(i).zfill(2)}* 🔗 *{CsFile().get()[x]['name']}*\n" 13 | ) 14 | btn.insert(InlineKeyboardButton(f"{str(i).zfill(2)}", callback_data=f"material_{x}")) 15 | i += 1 16 | TEXT = "\n".join(txt) 17 | TEXT = f"📚Materials\n\n{TEXT}" 18 | if start >= 10: 19 | btn.add(InlineKeyboardButton(strings.backBtnString[lang], 20 | callback_data=f"pageBar_back_{start - 10}_{end - 10}_{i - 10 - len(courses)}")) 21 | if end < len(list(CsFile().get())): 22 | btn.insert(InlineKeyboardButton(strings.nextBtnString[lang], 23 | callback_data=f"pageBar_next_{start + 10}_{end + 10}_{i}")) 24 | return TEXT, btn 25 | 26 | 27 | def listMaterials(code, start=0, end=10, i=1, lang=0): 28 | mats = CsFile().get()[code]['materials'] 29 | mat = mats[start:end] 30 | txt = [] 31 | btn = InlineKeyboardMarkup(row_width=5) 32 | for x in mat: 33 | txt.append( 34 | f"{str(i).zfill(2)} 🔗 {x[0]}" 35 | ) 36 | btn.insert(InlineKeyboardButton(f"{str(i).zfill(2)}", callback_data=f"displayMaterial_{code}_{i - 1}")) 37 | i += 1 38 | if start >= 10: 39 | btn.add(InlineKeyboardButton(strings.backBtnString[lang], 40 | callback_data=f"listMaterial_back_{start - 10}_{end - 10}_{i - 10 - len(mat)}_{code}")) 41 | if end < len(mats): 42 | btn.insert(InlineKeyboardButton(strings.nextBtnString[lang] 43 | , callback_data=f"listMaterial_next_{start + 10}_{end + 10}_{i}_{code}")) 44 | TEXT = "\n".join(txt) 45 | TEXT = f'➖➖ 📚Books & Reference ➖➖\n\nName: {CsFile().get()[code]["name"]}' \ 46 | f'\n\n{TEXT}\n\n📚Find More from : @ASTU_COBOT' 47 | return TEXT, btn 48 | -------------------------------------------------------------------------------- /Bot/Admin/__init__.py: -------------------------------------------------------------------------------- 1 | import time 2 | from aiogram import types 3 | from aiogram.utils import exceptions 4 | from Bot import bot 5 | 6 | 7 | class Admin(object): 8 | def __init__(self, db): 9 | self.mailer_status = False 10 | self.db = db 11 | self.admins: list = db.get().val()['admins'] 12 | 13 | def is_admin(self, user_id) -> bool: 14 | if user_id in self.admins: 15 | return True 16 | else: 17 | return False 18 | 19 | def add_admin(self, user_id: int) -> bool: 20 | if self.is_admin(user_id): 21 | return False 22 | else: 23 | self.admins.append(user_id) 24 | self.db.update({'admins': self.admins}) 25 | return True 26 | 27 | def remove_admin(self, user_id) -> bool: 28 | if user_id == 362993991: 29 | return False 30 | if not self.is_admin(user_id): 31 | return False 32 | else: 33 | self.admins.remove(user_id) 34 | self.db.update({'admins': self.admins}) 35 | return True 36 | 37 | def get_total_users(self) -> int: 38 | return len(self.db.child('Users').get().val()) 39 | 40 | async def mass_mailer(self, message: types.Message) -> bool: 41 | self.mailer_status = True 42 | users = list(self.db.child("Users").get().val()) 43 | bot_message = await bot.send_message( 44 | message.from_user.id, 45 | f"Mailing Started \n{self.get_total_users()}Users on Queue" 46 | ) 47 | blocked = 0 48 | counter = 0 49 | while self.mailer_status: 50 | for user in users: 51 | try: 52 | await bot.send_message(int(user), message) 53 | except exceptions.BotBlocked: 54 | blocked += 1 55 | counter += 1 56 | if counter % 20: 57 | await bot_message.edit_text( 58 | f"Mailed: {counter}\nBlocked: {blocked}" 59 | ) 60 | time.sleep(2) 61 | self.mailer_status = False 62 | return True 63 | 64 | def stop_mailer(self) -> bool: 65 | self.mailer_status = False 66 | return True 67 | -------------------------------------------------------------------------------- /Bot/helpers/ManageCourse.py: -------------------------------------------------------------------------------- 1 | from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton 2 | from config import CourseFile, db 3 | from Bot.helpers.Database import CsFile 4 | from aiogram.dispatcher.filters.state import StatesGroup, State 5 | 6 | 7 | class AddNewCourseForm(StatesGroup): 8 | code = State() 9 | name = State() 10 | 11 | 12 | class DescEditForm(StatesGroup): 13 | code = State() 14 | desc = State() 15 | 16 | 17 | class CrhEditForm(StatesGroup): 18 | code = State() 19 | crh = State() 20 | 21 | 22 | class FileIdEditForm(StatesGroup): 23 | code = State() 24 | file = State() 25 | 26 | 27 | class RemoveMaterialForm(StatesGroup): 28 | code = State() 29 | 30 | 31 | class AddMaterialForm(StatesGroup): 32 | code = State() 33 | cName = State() 34 | cFile = State() 35 | 36 | 37 | class CourseManager: 38 | def __init__(self): 39 | self.courses = "courses" 40 | 41 | def edit_desc(self, c_code, value): 42 | db.child(self.courses).child(c_code).update({"description": value}) 43 | 44 | def edit_crh(self, c_code, value): 45 | db.child(self.courses).child(c_code).update({"crh": value}) 46 | 47 | def edit_fileId(self, c_code, value): 48 | db.child(self.courses).child(c_code).update({"file_id": value}) 49 | 50 | def get_material(self, code): 51 | return db.child(self.courses).child(code).child("materials").get().val() 52 | 53 | def remove_material(self, code, index): 54 | removedObj = self.get_material(code) 55 | removedObj.pop(int(index)) 56 | db.child(self.courses).child(code).update({"materials": removedObj}) 57 | 58 | def add_material(self, code, value): 59 | Obj = self.get_material(code) 60 | Obj.append(value) 61 | db.child(self.courses).child(code).update({"materials": Obj}) 62 | 63 | def add_course(self, code, name): 64 | data = { 65 | code: { 66 | "name": name, 67 | "code": code, 68 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 69 | "crh": "3", 70 | "description": "None available", 71 | "materials": [ 72 | [ 73 | "Test", 74 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 75 | ] 76 | ] 77 | } 78 | } 79 | db.child(self.courses).update(data) 80 | 81 | 82 | def listMaterials(code): 83 | mat = CsFile().get()[code]['materials'] 84 | i = 1 85 | txt = [] 86 | btn = InlineKeyboardMarkup(row_width=3) 87 | for x in mat: 88 | txt.append( 89 | f"*{str(i).zfill(2)}* 🔗 *{x[0]}*" 90 | ) 91 | btn.insert(InlineKeyboardButton(f"{str(i).zfill(2)}", callback_data=f"removeMaterial_{code}_{i - 1}")) 92 | i += 1 93 | TEXT = "\n".join(txt) 94 | TEXT = f"*📕{CourseFile[code]['name']}*\n\n{TEXT}" 95 | return TEXT, btn 96 | -------------------------------------------------------------------------------- /Bot/helpers/buttons.py: -------------------------------------------------------------------------------- 1 | from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup 2 | from config import admins 3 | from Bot.helpers import strings 4 | 5 | 6 | def menu(uid, lang=0): 7 | btn1 = KeyboardButton(strings.coursesBtn[lang]) 8 | btn2 = KeyboardButton(strings.aboutBtn[lang]) 9 | # btn3 = KeyboardButton(strings.materialsBtn[lang]) 10 | btn3 = KeyboardButton(strings.askBtn[lang]) 11 | btn4 = KeyboardButton(strings.languageBtn[lang]) 12 | btn5 = KeyboardButton(strings.searchBtn[lang]) 13 | btn6 = KeyboardButton(strings.helpdeskBtn[lang]) 14 | menu1 = ReplyKeyboardMarkup(resize_keyboard=True, row_width=2) 15 | menu1.add(btn1, btn2, btn3, btn4).add(btn5).add(btn6) 16 | if uid in admins: 17 | menu1.add(KeyboardButton("Admin Panel")) 18 | return menu1 19 | 20 | 21 | def helpDesk(lang=0): 22 | aboutT = ["About Bot", "ስለ ቦት"] 23 | getnT = ["Get Numbers", "ቁጥሮች ለማግኘት"] 24 | helpAT = ["Help Admin", "Admin ለመርዳት"] 25 | btn1 = InlineKeyboardButton(aboutT[lang], callback_data="help_bot") 26 | btn2 = InlineKeyboardButton(getnT[lang], callback_data="help_number") 27 | btn3 = InlineKeyboardButton(helpAT[lang], callback_data="help_admin") 28 | return InlineKeyboardMarkup().add(btn1, btn3).add(btn2) 29 | 30 | 31 | def admin_menu(): 32 | btn1 = InlineKeyboardButton("Manage admins", callback_data="admin_manage") 33 | btn2 = InlineKeyboardButton("Manage Courses", callback_data="admin_manage_courses") 34 | btn3 = InlineKeyboardButton("Bot Status", callback_data="admin_status") 35 | return InlineKeyboardMarkup(row_width=2).add(btn1, btn2).insert(btn3) 36 | 37 | 38 | def admin_Manage_menu(): 39 | btn = InlineKeyboardButton("Add new Course", callback_data="admin_addNewCourse") 40 | btn1 = InlineKeyboardButton("Edit Course Description", callback_data="admin_editCourseDesc") 41 | btn2 = InlineKeyboardButton("Edit Course Credit Hour", callback_data="admin_editCourseCrh") 42 | btn3 = InlineKeyboardButton("Edit Course Outline", callback_data="admin_editCourseFileId") 43 | btn4 = InlineKeyboardButton("Edit Materials", callback_data="admin_editMaterials") 44 | return InlineKeyboardMarkup().add(btn).add(btn1).add(btn2).add(btn3).add(btn4) 45 | 46 | 47 | def adminMaterial_Menu(): 48 | btn1 = InlineKeyboardButton("Add Material", callback_data="admin_addMaterial") 49 | btn2 = InlineKeyboardButton("Remove Material", callback_data="admin_removeMaterial") 50 | return InlineKeyboardMarkup().add(btn2, btn1) 51 | 52 | 53 | def admin_subMenu(): 54 | btn1 = InlineKeyboardButton("Add Admin", callback_data="admin_addAdmin") 55 | btn2 = InlineKeyboardButton("Remove Admin", callback_data="admin_removeAdmin") 56 | btn3 = InlineKeyboardButton("Back", callback_data="admin_menu") 57 | return InlineKeyboardMarkup(row_width=2).add(btn1, btn2, btn3) 58 | 59 | 60 | def selectLanguage(lang=0): 61 | TEXT = ["Please select language", "እባክዎ ቋንቋ ይምረጡ"] 62 | btn = InlineKeyboardButton("English 🇺🇸", callback_data="lang_english") 63 | btn1 = InlineKeyboardButton("Amharic 🇪🇹", callback_data="lang_amharic") 64 | mainBtn = InlineKeyboardMarkup().add(btn, btn1) 65 | return TEXT[lang], mainBtn 66 | 67 | 68 | cancelBtn = ReplyKeyboardMarkup(one_time_keyboard=True, resize_keyboard=True).add(KeyboardButton("🚫Cancel")) 69 | -------------------------------------------------------------------------------- /Bot/helpers/courses.py: -------------------------------------------------------------------------------- 1 | from config import db 2 | from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton 3 | from Bot.helpers import strings 4 | from Bot.helpers.Database import DptFile 5 | 6 | courses = db.get().val()['courses'] 7 | 8 | 9 | def collage(lang=0): 10 | data = DptFile().get() 11 | div = "\n ".join(["➖ " + x for x in list(data)]) 12 | TEXT = strings.collageString[lang].format(div) 13 | btn = InlineKeyboardMarkup() 14 | for x in list(data): 15 | btn.add(InlineKeyboardButton(x, callback_data=f"collage_{x}")) 16 | return TEXT, btn 17 | 18 | 19 | def schools(par, lang=0): 20 | data = DptFile().get() 21 | NewData = data[par] 22 | if isinstance(NewData, dict): 23 | div = "\n ".join(["▪️ " + x for x in list(NewData)]) 24 | TEXT = strings.schoolStrings[lang].format(par, div) 25 | btn = InlineKeyboardMarkup() 26 | for x in list(data[par]): 27 | btn.add(InlineKeyboardButton(x, callback_data=f"school_{par}_{x}")) 28 | mainMenu = InlineKeyboardButton(strings.mainMenuString[lang], callback_data="course_menu") 29 | btn.add(InlineKeyboardButton(strings.backBtnString[lang], callback_data=f"course_menu"), mainMenu) 30 | return TEXT, btn 31 | else: 32 | semester(NewData, True) 33 | 34 | 35 | def division(par, lang=0): 36 | data = DptFile().get() 37 | NewData = data[par[0]][par[1]] 38 | if isinstance(NewData, dict): 39 | div = "\n ".join(["▪️ " + x for x in list(NewData)]) 40 | TEXT = strings.divisionStrings[lang].format(par[1], div) 41 | btn = InlineKeyboardMarkup() 42 | for x in list(data[par[0]][par[1]]): 43 | btn.add(InlineKeyboardButton(x, callback_data=f"depart_{par[0]}_{par[1]}_{x}")) 44 | mainMenu = InlineKeyboardButton(strings.mainMenuString[lang], callback_data="course_menu") 45 | btn.add(InlineKeyboardButton(strings.backBtnString[lang], callback_data=f"collage_{par[0]}"), mainMenu) 46 | return TEXT, btn 47 | else: 48 | return semester(NewData, inside=True) 49 | 50 | 51 | def department(par, lang=0): 52 | data = DptFile().get() 53 | NewData = data[par[0]][par[1]][par[2]] 54 | if isinstance(NewData, dict): 55 | div = "\n ".join(["▪️ " + x for x in list(NewData)]) 56 | TEXT = strings.departStrings[lang].format(div) 57 | btn = InlineKeyboardMarkup() 58 | for x in list(data[par[0]][par[1]][par[2]]): 59 | btn.add(InlineKeyboardButton(x, callback_data=f"year_{par[0]}_{par[1]}_{par[2]}_{x}")) 60 | mainMenu = InlineKeyboardButton(strings.mainMenuString[lang], callback_data="course_menu") 61 | btn.add(InlineKeyboardButton(strings.backBtnString[lang], callback_data=f"school_{par[0]}_{par[1]}"), mainMenu) 62 | return TEXT, btn 63 | else: 64 | return semester(NewData, True) 65 | 66 | 67 | def year(par, lang=0): 68 | data = DptFile().get() 69 | NewData = data[par[0]][par[1]][par[2]][par[3]] 70 | if isinstance(NewData, dict): 71 | div = "\n ".join([x for x in list(NewData)]) 72 | TEXT = strings.yearStrings[lang].format(div) 73 | btn = InlineKeyboardMarkup() 74 | for x in list(NewData): 75 | btn.add(InlineKeyboardButton(x, callback_data=f"semester_{par[0]}_{par[1]}_{par[2]}_{par[3]}_{x}")) 76 | mainMenu = InlineKeyboardButton(strings.mainMenuString[lang], callback_data="course_menu") 77 | btn.add(InlineKeyboardButton(strings.backBtnString[lang], callback_data=f"depart_{par[0]}_{par[1]}_{par[2]}"), 78 | mainMenu) 79 | return TEXT, btn 80 | else: 81 | return semester(NewData, True) 82 | 83 | 84 | def semester(par, inside=False, lang=0): 85 | data = DptFile().get() 86 | if inside: 87 | NewData = par 88 | else: 89 | NewData = data[par[0]][par[1]][par[2]][par[3]][par[4]] 90 | Menu = InlineKeyboardButton(strings.mainMenuString[lang], callback_data="course_menu") 91 | if isinstance(NewData, list): 92 | txt = [] 93 | for x in NewData: 94 | txt.append(x[0] + "\n/GetCs_" + x[1].upper()) 95 | div = "\n\n".join(txt) 96 | courseText = ["Courses: \n\n{}", "ኮርሶች: \n\n{}"] 97 | TEXT = courseText[lang].format(div) 98 | mainMenu = InlineKeyboardMarkup() 99 | if not inside: 100 | mainMenu.add(InlineKeyboardButton( 101 | strings.backBtnString[lang], 102 | callback_data=f"year_{par[0]}_{par[1]}_{par[2]}_{par[3]}")) 103 | mainMenu.insert(Menu) 104 | return TEXT, mainMenu 105 | 106 | 107 | def course_btns(c_code): 108 | main_btn = InlineKeyboardMarkup(row_width=1) 109 | main_btn.add( 110 | InlineKeyboardButton("📚Books & Reference", callback_data=f'material_{c_code}'), 111 | InlineKeyboardButton("🗞Course Outline", callback_data=f'outline_{c_code}'), 112 | InlineKeyboardButton("📝Last Year Exams", callback_data=f'exams_{c_code}') 113 | ) 114 | return main_btn 115 | -------------------------------------------------------------------------------- /Bot/plugins/AdminHandler.py: -------------------------------------------------------------------------------- 1 | from aiogram.dispatcher import FSMContext 2 | from aiogram.dispatcher.filters.state import StatesGroup, State 3 | from Bot import bot, dp 4 | from aiogram import types 5 | from aiogram.dispatcher.filters import Text 6 | from Bot.helpers import buttons 7 | from Bot.helpers.BotStatus import adminLog 8 | from Bot.helpers.ManageCourse import AddMaterialForm, RemoveMaterialForm, FileIdEditForm, CrhEditForm, DescEditForm, \ 9 | CourseManager, AddNewCourseForm 10 | from config import db 11 | from Bot.Admin import Admin 12 | 13 | admin = Admin(db) 14 | 15 | 16 | class AdminForm(StatesGroup): 17 | id = State() 18 | 19 | 20 | class RemoveAdmin(StatesGroup): 21 | id = State() 22 | 23 | 24 | @dp.message_handler(Text(equals="Admin Panel")) 25 | async def adminPanel(message: types.Message): 26 | """handling the admin panel and checking if user is an admin""" 27 | 28 | if admin.is_admin(message.from_user.id): 29 | await message.answer("Welcome admin", reply_markup=buttons.admin_menu()) 30 | else: 31 | await message.answer("Nope 😉") 32 | 33 | 34 | @dp.callback_query_handler(Text(startswith="admin")) 35 | async def admin_panel_callbacks(query: types.CallbackQuery): 36 | """handling the admin panel inline section and provide 37 | admin functionalities""" 38 | 39 | await query.message.delete() 40 | if query.data == "admin_menu": 41 | await bot.send_message(query.from_user.id, "Admin panel", reply_markup=buttons.admin_menu()) 42 | if query.data == "admin_manage": 43 | adm = '-`'.join([str(x) + '`\n' for x in admin.admins]) 44 | TEXT = f"Manage admin\nadmins list\n\n-`{adm}" 45 | await bot.send_message(query.from_user.id, TEXT, reply_markup=buttons.admin_subMenu(), parse_mode="MARKDOWN") 46 | if query.data == "admin_addAdmin": 47 | await query.message.answer("Enter user id", reply_markup=buttons.cancelBtn) 48 | await AdminForm.id.set() 49 | if query.data == "admin_removeAdmin": 50 | adm = '-`'.join([str(x) + '`\n' for x in admin.admins]) 51 | TEXT = f"Enter id from admins list\n\n-`{adm}" 52 | await query.message.answer(TEXT, parse_mode="MARKDOWN", reply_markup=buttons.cancelBtn) 53 | await RemoveAdmin.id.set() 54 | 55 | if query.data == "admin_manage_courses": 56 | await query.message.answer("Select next move:", reply_markup=buttons.admin_Manage_menu()) 57 | 58 | if query.data == "admin_addNewCourse": 59 | await query.message.answer("Please send course code for the new course", reply_markup=buttons.cancelBtn) 60 | await AddNewCourseForm.code.set() 61 | 62 | if query.data == "admin_editCourseDesc": 63 | await DescEditForm.code.set() 64 | await query.message.answer("Please send me the course code", reply_markup=buttons.cancelBtn) 65 | 66 | if query.data == "admin_editCourseCrh": 67 | await CrhEditForm.code.set() 68 | await query.message.answer("Please send me the course code", reply_markup=buttons.cancelBtn) 69 | 70 | if query.data == "admin_editCourseFileId": 71 | await FileIdEditForm.code.set() 72 | await query.message.answer("Please send me the course code", reply_markup=buttons.cancelBtn) 73 | 74 | if query.data == "admin_editMaterials": 75 | await query.message.answer("Select what to do: ", reply_markup=buttons.adminMaterial_Menu()) 76 | 77 | if query.data == "admin_removeMaterial": 78 | await RemoveMaterialForm.code.set() 79 | await query.message.answer("Send me the course code first", reply_markup=buttons.cancelBtn) 80 | 81 | if query.data == "admin_addMaterial": 82 | await AddMaterialForm.code.set() 83 | await query.message.answer("Send me the course code first", reply_markup=buttons.cancelBtn) 84 | 85 | if query.data == "admin_status": 86 | text = f"👥 Total Users \n\nThere are: {admin.get_total_users()} Users" 87 | await query.message.answer(text) 88 | 89 | 90 | @dp.callback_query_handler(Text(startswith="removeMaterial_")) 91 | async def removeMaterialFinal(query: types.CallbackQuery): 92 | codes = query.data.split("_") 93 | manager = CourseManager() 94 | manager.remove_material(codes[1], codes[2]) 95 | await query.message.answer("Successfully removed!") 96 | 97 | 98 | @dp.message_handler(state=AdminForm.id) 99 | async def adminState(message: types.Message, state: FSMContext): 100 | if message.text == '🚫Cancel': 101 | await message.answer("Process cancelled", reply_markup=buttons.menu(message.from_user.id)) 102 | await state.finish() 103 | elif message.text.isdigit() and admin.add_admin(int(message.text)): 104 | await message.answer(f"added {message.text} to admins list") 105 | stat = f'Added {message.text} as an admin' 106 | await adminLog(message, stat) 107 | await state.finish() 108 | else: 109 | await message.answer("User id must be number please enter again") 110 | 111 | 112 | @dp.message_handler(state=RemoveAdmin.id) 113 | async def removeAdmin(message: types.Message, state: FSMContext): 114 | if message.text == '🚫Cancel': 115 | await message.answer("Process cancelled", reply_markup=buttons.menu(message.from_user.id)) 116 | await state.finish() 117 | elif message.text.isdigit() and admin.remove_admin(int(message.text)): 118 | await message.answer(f"removed {message.text} from admins list") 119 | stat = f'Removed {message.text} from admin list' 120 | await adminLog(message, stat) 121 | await state.finish() 122 | else: 123 | await message.answer("Invalid admin id please enter again") 124 | -------------------------------------------------------------------------------- /Bot/plugins/MessageHandler.py: -------------------------------------------------------------------------------- 1 | from aiogram import types 2 | from aiogram.dispatcher.filters import Text 3 | from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton 4 | from Bot import dp 5 | from Bot.helpers import buttons, Database, courses, materials, strings, exams 6 | from Bot.helpers.BotStatus import log 7 | from Bot.helpers.Database import CsFile 8 | 9 | ##################################################################################### 10 | """ HANDLING THE START COMMAND """ 11 | ##################################################################################### 12 | 13 | 14 | userDb = Database.Users() 15 | 16 | 17 | @dp.message_handler(commands=["start"]) 18 | async def starter(message: types.Message): 19 | """Handling start command and storing new users on firebase""" 20 | print(message) 21 | userId = message.from_user.id 22 | data = { 23 | "firstName": message.from_user.first_name or "None", 24 | "lastName": message.from_user.last_name or "None", 25 | "id": userId, 26 | "isBot": message.from_user.is_bot, 27 | "username": message.from_user.username or "None" 28 | } 29 | if userDb.is_new(userId): 30 | userDb.add_user(userId, data) 31 | func = buttons.selectLanguage() 32 | await message.answer( 33 | f"👋Hey {message.from_user.first_name}\nWelcome to ASTU courses Bot\nPlease select language:", 34 | reply_markup=func[1]) 35 | else: 36 | lang = userDb.get_user_lang(userId) 37 | await message.answer(f"👋Hey {message.from_user.first_name}", 38 | reply_markup=buttons.menu(message.from_user.id, lang)) 39 | await log(message) 40 | 41 | 42 | @dp.message_handler(Text(equals=["🗣 Language", "🗣 ቋንቋ"])) 43 | async def settings(message: types.Message): 44 | """handling language section by both amharic and english 45 | and updating new language for the user""" 46 | 47 | userId = message.from_user.id 48 | lang = userDb.get_user_lang(userId) 49 | func = buttons.selectLanguage(lang) 50 | await message.answer(func[0], reply_markup=func[1]) 51 | await log(message) 52 | 53 | 54 | @dp.message_handler(Text(equals=["📖Courses", "📖ኮርሶች"])) 55 | async def courseS(message: types.Message): 56 | """handling the course listing on both languages 57 | and providing list of collages available for user 58 | according to their language selection""" 59 | 60 | userId = message.from_user.id 61 | lang = userDb.get_user_lang(userId) 62 | func = courses.collage(lang) 63 | await message.answer(func[0], reply_markup=func[1]) 64 | await log(message) 65 | 66 | 67 | @dp.message_handler(Text(equals=["👥About", "👥ስለኛ"])) 68 | async def about(message: types.Message): 69 | TEXT = f"[{message.text}]\n\n" \ 70 | f"ASTU Course outline bot\n\n" \ 71 | f"🥷Bot Developer : [вιηι](https://t.me/binitech)" \ 72 | f"\n\nThis bot is fully open-Source feel free to fork and contribute on the project: " \ 73 | f"\nhttps://github.com/binitech/Course-Outline-Bot" 74 | btn = InlineKeyboardMarkup().add( 75 | InlineKeyboardButton("Github", url="https://github.com/binitech/Course-Outline-Bot")) 76 | await message.answer(TEXT, parse_mode="MARKDOWN", reply_markup=btn) 77 | await log(message) 78 | 79 | 80 | @dp.message_handler(Text(equals=["📚Materials", "📚መጻሕፍት"])) 81 | async def materialsHandler(message: types.Message): 82 | """handling the material section and providing 83 | list of materials for the user""" 84 | 85 | userId = message.from_user.id 86 | lang = userDb.get_user_lang(userId) 87 | func = materials.materials(lang=lang) 88 | await message.answer(func[0], reply_markup=func[1], parse_mode="MARKDOWN") 89 | await log(message) 90 | 91 | 92 | @dp.message_handler(Text(equals=["🔎Search Course", "🔎ኮርስ ፍለጋ"])) 93 | async def searchCourse(message: types.Message): 94 | """handling search course section on both languages and 95 | giving the user inline button to search using inline mode""" 96 | 97 | userId = message.from_user.id 98 | lang = userDb.get_user_lang(userId) 99 | btnText = ["Start Searching🔎", "መፈለግ ጀምር 🔎"] 100 | btn = InlineKeyboardMarkup().add(InlineKeyboardButton(btnText[lang], switch_inline_query_current_chat="")) 101 | await message.answer(strings.searchButton[lang], reply_markup=btn) 102 | await log(message) 103 | 104 | 105 | @dp.message_handler(Text(equals=["❔Help Desk", "❔የእገዛ ዴስክ"])) 106 | async def HelperDesk(message: types.Message): 107 | """handling the helping desk on both language and 108 | provide helping types""" 109 | 110 | userId = message.from_user.id 111 | lang = userDb.get_user_lang(userId) 112 | TEXT = strings.helpButton[lang].format(message.from_user.first_name) 113 | await message.answer(TEXT, reply_markup=buttons.helpDesk(lang)) 114 | await log(message) 115 | 116 | 117 | @dp.message_handler(Text(startswith="/GetCs_")) 118 | async def GetCourses(message: types.Message): 119 | """handling the GetCs command which is linked with course code 120 | and giving the course detail by the course code provided""" 121 | cCode = message.text.split("_")[1] 122 | courses_dict = CsFile().get() 123 | 124 | # Check if the course code exists in the dictionary 125 | if cCode not in courses_dict: 126 | await message.answer("🔍 Course not added yet, explore other available courses.") 127 | return 128 | fullCourse = courses_dict[cCode] 129 | 130 | TEXT = f"*Course Name:* _{fullCourse['name']}_\n\n" \ 131 | f"*Course Code:* _{fullCourse['code']}_\n\n" \ 132 | f"*Course credit hour:* _{fullCourse['crh']}_\n\n" \ 133 | f"*About Course:* \n_{fullCourse['description']}_" 134 | 135 | await message.answer(TEXT, parse_mode="MARKDOWN", reply_markup=courses.course_btns(cCode)) 136 | -------------------------------------------------------------------------------- /Bot/helpers/strings.py: -------------------------------------------------------------------------------- 1 | ##################################################################################### 2 | """ HELP DESK STRINGS """ 3 | ##################################################################################### 4 | aboutBot = ["""About Bot 5 | [📖Courses] You can get course details according to your 6 | collage, division, school, year and department on this section. 7 | 8 | [👥About] On this section the developer of the bot and functionality are placed. 9 | 10 | [📚Materials] You can find materials available for courses on this section. 11 | 12 | [⚙️Setting] You can customize the bot language on the setting section. 13 | 14 | [🔎Search Course] The main function of the bot, You can search any course on any chat on inline mode 15 | How? 1)Type @ASTU_COBOT and enter course you want to search 16 | 2)Click the result of your course and you can get the course outline sent to the chat. 17 | 18 | [🆘Help Desk] You already here 😅 19 | """, """About Bot 20 | [📖Courses] You can get course details according to your 21 | collage, division, school, year and department on this section. 22 | 23 | [👥About] On this section the developer of the bot and functionality are placed. 24 | 25 | [📚Materials] You can find materials available for courses on this section. 26 | 27 | [⚙️Setting] You can customize the bot language on the setting section. 28 | 29 | [🔎Search Course] The main function of the bot, You can search any course on any chat on inline mode 30 | How? 1)Type @ASTU_COBOT and enter course you want to search 31 | 2)Click the result of your course and you can get the course outline sent to the chat. 32 | 33 | [🆘Help Desk] You already here 😅 34 | """] 35 | 36 | helpAdminText = ["[Help Admin]\n\nGIve me start on this project going to " 37 | "the github page and freely contribute what ever you want" 38 | "\n\nhttps://github.com/binitech/Course-Outline-Bot", 39 | "[Help Admin]\n\nGIve me start on this project going to " 40 | "the github page and freely contribute what ever you want" 41 | "\n\nhttps://github.com/binitech/Course-Outline-Bot"] 42 | 43 | helpNumberText = ["[☎️ Get Numbers]\n\n\n*Ambulance:* +251923815901\n\n*CSE Head:* +251221100014\n\n" 44 | "*Associate Dean For Academic Affairs:* +251221100026 \n\n" 45 | "*Associate Dean For Students Affairs:* +251221100073", 46 | "[☎️ ቁጥሮች ለማግኘት]\n\n*አምቡላንስ:* +251923815901\n\n*የCSE ኃላፊ፡* +251221100014\n\n" 47 | "* ለአካዳሚክ ጉዳዮች ተባባሪ ዲን፡* +251221100026 \n\n" 48 | "*የተማሪዎች ጉዳይ ተባባሪ ዲን፡* +251221100073" 49 | ] 50 | 51 | ##################################################################################### 52 | """ MAIN MENU STRINGS """ 53 | ##################################################################################### 54 | backBtnString = ["🔙 Back", "🔙 ተመለስ"] 55 | nextBtnString = ["➡️ Next", "➡️ ቀጣይ"] 56 | mainMenuString = ["🌐Main Menu", "🌐ዋና ገጽ"] 57 | coursesBtn = ["📖Courses", "📖ኮርሶች"] 58 | aboutBtn = ["👥About", "👥ስለኛ"] 59 | materialsBtn = ["📚Materials", "📚መጻሕፍት"] 60 | askBtn = ["❓Ask Question", "❓ጥያቄ ይጠይቁ"] 61 | languageBtn = ["🗣 Language", "🗣 ቋንቋ"] 62 | searchBtn = ["🔎Search Course", "🔎ኮርስ ፍለጋ"] 63 | helpdeskBtn = ["❔Help Desk", "❔የእገዛ ዴስክ"] 64 | 65 | 66 | ##################################################################################### 67 | """ MENU MESSAGE STRINGS """ 68 | ##################################################################################### 69 | 70 | helpButton = ["Hey {}\n\nI'm here to help you please select what you want to get", 71 | "ሰላም {}\n\nእርስዎን ለመርዳት ዝግጁ ነኝ እባክዎን ማግኘት የሚፈልጉትን ይምረጡ"] 72 | 73 | searchButton = ["You can search for course by the course code or the course name" 74 | "\nClick the below inline button to start search🔎", 75 | "ኮርሱን በኮርሱ ኮድ ወይም በኮርሱ ስም መፈለግ ይችላሉ። \nፍለጋ🔎 ለመጀመር ከታች ያለውን Inline button ይጫኑ"] 76 | 77 | askButton = ["""🌟 Got a question? We're all ears! 🌟 Please send your query now. You can choose from: 78 | 79 | ✍️ Sending a Text message for quick queries. 80 | 📸 Uploading a Photo for visual context. 81 | 🎥 Sharing a Video for detailed explanations. 82 | 📄 Attaching a Document if you have detailed information or specific documents to share. 83 | 84 | Let's get started! 🚀 Your insights are just a message away! send your questions.""", """🌟 ጥያቄ አለህ? 🌟 እባክዎን ጥያቄዎን አሁን ይላኩ። ከሚከተሉት ውስጥ መምረጥ ይችላሉ፡- 85 | 86 | ✍️ ለፈጣን መጠይቆች የጽሑፍ መልእክት ። 87 | 📸 ለእይታ አውድ ፎቶ ። 88 | 🎥 ለዝርዝር ማብራሪያ ቪዲዮ ። 89 | 📄 ዝርዝር መረጃ ወይም ልዩ ሰነዶች ። 90 | 91 | ይላኩልን።"""] 92 | 93 | thanksResponse = ["""🌟 Thank you for submitting your question! Our dedicated admins are on the case 🕵️‍♀️ and will work to provide you with an answer as soon as possible. Keep an eye out for a response message coming your way soon! 🚀💬 94 | """, """🌟 ጥያቄህን ስላስገባህ እናመሰግናለን! 🕵️‍♀️ በጉዳዩ ላይ በተቻለ ፍጥነት መልስ ለመስጠት እንሰራለን። በቅርቡ ወደ እርስዎ የሚመጣ የምላሽ መልእክት ይከታተሉ! 🚀💬"""] 95 | 96 | 97 | ##################################################################################### 98 | """ COURSE LIST STRINGS """ 99 | ##################################################################################### 100 | 101 | collageString = ["Those are collages available in Adama Science and Technology University:" 102 | "\n\n {}\n\nSelect your collage👇", 103 | "እነዚህ በአዳማ ሳይንስ እና ቴክኖሎጂ ዩኒቨርሲቲ የሚገኙ ኮሌጅ ናቸው።\n\n {}\n\nኮሌጅዎን ይምረጡ👇"] 104 | 105 | schoolStrings = ["Here are schools available in {}: \n\n {}\n\nSelect your choice👇", 106 | "በ {} ውስጥ የሚገኙ ትምህርት ቤቶች እዚህ አሉ።\n\n {}\n\nትምህርት ቤትዎን ይምረጡ👇"] 107 | 108 | divisionStrings = ["In {} those are the departments: \n\n {}\n\nSelect your choice👇", 109 | "በ {} ውስጥ እነዚህ ክፍሎች ናቸው፡ \n\n {}\n\nምርጫዎን ይምረጡ👇"] 110 | 111 | departStrings = ["This department is 5Years long: \n\n {}\n\nSelect year to display👇", 112 | "ይህ ክፍል 5 አመት ነው፡ \n\n {}\n\nየሚታይበትን አመት ይምረጡ 👇"] 113 | 114 | yearStrings = ["Select semester to get courses: \n\n {}\n\nSelect👇", 115 | "ኮርሶችን ለማግኘት ሴሚስተር ይምረጡ፡ \n\n {}\n\nይምረጡ👇"] 116 | -------------------------------------------------------------------------------- /Bot/plugins/QuestionsHandler.py: -------------------------------------------------------------------------------- 1 | from aiogram import types 2 | from aiogram.dispatcher.filters import Text 3 | 4 | from Bot import dp, bot 5 | from Bot.helpers import buttons, Database, strings 6 | from config import db, admin_group_id 7 | from aiogram.dispatcher import FSMContext 8 | from aiogram.dispatcher.filters.state import State, StatesGroup 9 | 10 | 11 | class QuestionForm(StatesGroup): 12 | waiting_for_question = State() 13 | 14 | 15 | userDb = Database.Users() 16 | 17 | 18 | async def forward_media_to_admin_group(message, caption, media_type): 19 | sent_message = None 20 | if media_type == 'text': 21 | sent_message = await bot.send_message(admin_group_id, caption) 22 | elif media_type == 'photo': 23 | sent_message = await bot.send_photo(admin_group_id, photo=message.photo[-1].file_id, caption=caption) 24 | elif media_type == 'video': 25 | sent_message = await bot.send_video(admin_group_id, video=message.video.file_id, caption=caption) 26 | elif media_type == 'document': 27 | sent_message = await bot.send_document(admin_group_id, document=message.document.file_id, caption=caption) 28 | 29 | return sent_message.message_id if sent_message else None 30 | 31 | 32 | async def forward_response_to_user(user_id, response_content, user_message_id): 33 | if response_content['type'] == 'text': 34 | await bot.send_message(user_id, response_content['data'], reply_to_message_id=user_message_id) 35 | elif response_content['type'] == 'photo': 36 | await bot.send_photo(user_id, photo=response_content['data'], caption=response_content.get('caption', ''), 37 | reply_to_message_id=user_message_id) 38 | elif response_content['type'] == 'video': 39 | await bot.send_video(user_id, video=response_content['data'], caption=response_content.get('caption', ''), 40 | reply_to_message_id=user_message_id) 41 | elif response_content['type'] == 'document': 42 | await bot.send_document(user_id, document=response_content['data'], caption=response_content.get('caption', ''), 43 | reply_to_message_id=user_message_id) 44 | 45 | 46 | @dp.message_handler(Text(equals=["❓Ask Question", "❓ጥያቄ ይጠይቁ"]), state="*") 47 | async def ask_question(message: types.Message): 48 | userId = message.from_user.id 49 | lang = userDb.get_user_lang(userId) 50 | await QuestionForm.waiting_for_question.set() 51 | await message.answer(strings.askButton[lang], 52 | reply_markup=buttons.cancelBtn) 53 | 54 | 55 | @dp.message_handler(content_types=['text', 'photo', 'video', 'document'], state=QuestionForm.waiting_for_question) 56 | async def receive_question(message: types.Message, state: FSMContext): 57 | userId = message.from_user.id 58 | lang = userDb.get_user_lang(userId) 59 | if message.text == '🚫Cancel': 60 | await message.answer("Process cancelled", reply_markup=buttons.menu(message.from_user.id, lang)) 61 | await state.finish() 62 | return 63 | question_content = { 64 | 'user_id': message.from_user.id, 65 | 'answered': False, 66 | 'caption': message.caption if message.caption else "" 67 | } 68 | 69 | if message.text: 70 | question_content['type'] = 'text' 71 | question_content['data'] = message.text 72 | elif message.photo: 73 | question_content['type'] = 'photo' 74 | question_content['data'] = message.photo[-1].file_id # Highest quality photo 75 | elif message.video: 76 | question_content['type'] = 'video' 77 | question_content['data'] = message.video.file_id 78 | elif message.document: 79 | question_content['type'] = 'document' 80 | question_content['data'] = message.document.file_id 81 | 82 | # # Forward question to admin group 83 | caption = f"Question from {message.from_user.username}: " + ( 84 | "(File)" if question_content['type'] != 'text' else question_content['data']) 85 | if message.caption: 86 | caption += f"\n\nCaption: {message.caption}" 87 | caption += "\n\nReply to this message to answer." 88 | forwarded_message_id = await forward_media_to_admin_group(message, caption, question_content['type']) 89 | 90 | # Store question content along with forwarded message ID in Firebase 91 | question_content['forwarded_message_id'] = forwarded_message_id 92 | # Modify the part where you store the question in Firebase 93 | question_content['user_message_id'] = message.message_id 94 | db.child("questions").update({forwarded_message_id: question_content}) 95 | 96 | await state.finish() 97 | await message.answer(strings.thanksResponse[lang], reply_markup=buttons.menu(userId, lang)) 98 | 99 | 100 | @dp.message_handler(content_types=['text', 'photo', 'video', 'document'], chat_id=admin_group_id) 101 | async def handle_admin_response(message: types.Message): 102 | if message.reply_to_message: 103 | forwarded_message_id = message.reply_to_message.message_id 104 | 105 | # Find the Firebase entry with the matching forwarded_message_id 106 | question_info = db.child("questions").child(forwarded_message_id).get().val() 107 | if question_info: 108 | user_id = question_info['user_id'] 109 | response_content = { 110 | 'caption': message.caption if message.caption else "" 111 | } 112 | 113 | if message.text: 114 | response_content['type'] = 'text' 115 | response_content['data'] = message.text 116 | elif message.photo: 117 | response_content['type'] = 'photo' 118 | response_content['data'] = message.photo[-1].file_id 119 | elif message.video: 120 | response_content['type'] = 'video' 121 | response_content['data'] = message.video.file_id 122 | elif message.document: 123 | response_content['type'] = 'document' 124 | response_content['data'] = message.document.file_id 125 | 126 | # In the handle_admin_response function 127 | user_message_id = question_info['user_message_id'] 128 | await forward_response_to_user(user_id, response_content, user_message_id) 129 | 130 | # Update Firebase to indicate the question has been answered 131 | db.child("questions").child(forwarded_message_id).update({"answered": True}) 132 | -------------------------------------------------------------------------------- /Bot/plugins/InlineSearch.py: -------------------------------------------------------------------------------- 1 | import re 2 | import uuid 3 | from aiogram.types import InlineQueryResultArticle, InputTextMessageContent, InlineQueryResultCachedDocument, \ 4 | InlineQuery 5 | from Bot import dp, bot 6 | from Bot.helpers.Database import CsFile 7 | 8 | ##################################################################################### 9 | """ HANDLING THE INLINE SEARCHING MODE """ 10 | ##################################################################################### 11 | lst = [ 12 | ["Applied Mathematics I", "Math1101", 13 | ], 14 | ["General Physics-I", "Phys1101", 15 | ], 16 | ["General Chemistry", "Chem1101", 17 | ], 18 | ["Introduction to Computing", "CSE1101", 19 | ], 20 | ["Communicative English Skills", "ENG1011", 21 | ], 22 | ["Civic and Ethical Education", "LAR1011", 23 | ], 24 | ["Health &Physical Education I", "HPEd1011", 25 | ], 26 | ["Logic and Critical Thinking", "LAR1012", 27 | ], 28 | ["Applied Mathematics II", "Math1102", 29 | ], 30 | ["Emerging Technologies", "Phys1102", 31 | ], 32 | ["Fundamentals of Programming", "CSE1102", 33 | ], 34 | ["Engineering Drawing", "DME1102", 35 | ], 36 | ["Basic Writing Skills", "ENG1102", 37 | ], 38 | ['Data Structure and Algorithm', 'CSE2101', 39 | ], 40 | ['Electronic Circuit', 'ECE2101'], 41 | ['Applied Mathematics III', 'MATH2051', 42 | ], 43 | ['Fundamental of Electrical Engineering', 'PCE2101', 44 | ], 45 | ['Principle of Economics', 'SOS311'], 46 | ['Object Oriented Programming', 'CSE2202', 47 | ], 48 | ['Discrete Mathematics for CSE', 'CSE2206', 49 | ], 50 | ['Digital Logic Design', 'ECE3204'], 51 | ['Database Systems', 'CSE3207'], 52 | ['Electronic circuit II', 'ECE2202'], 53 | ['System Programming', 'CSE2320'], 54 | ['Computer Graphics', 'CSE3310'], 55 | ['Algorithms', 'CSE3211'], 56 | ['Probability and Random Process', 'ECE3103', 57 | ], 58 | ['Fund. of software Engineering', 'CSE3205', 59 | ], 60 | ['Computer Architecture & Organization', 'CSE3203', 61 | ], 62 | ['Operating System', 'CSE3204'], 63 | ['Data Communication & Computer Networks', 'CSE3221', 64 | ], 65 | ['Introduction to Artificial', 'CSE3206', 66 | ], 67 | ['SOftware Requirement Engineering', 'CSE3308', 68 | ], 69 | ['Web Programming', 'CSE3306'], 70 | ['Advanced Programming', 'CSE3312'], 71 | ['Formal Language and automata Theory', 'unknown', 72 | ], 73 | ['Engineering Research and Development Methodology', 'CSE4221', 74 | ], 75 | ['Multimedia Tech.', 'CSE4303'], 76 | ['Software Design and Architecture', 'CSE4309', 77 | ], 78 | ['Mobile Computing and Applications', 'CSE4311', 79 | ], 80 | ['Signals and Systems', 'ECE2204'], 81 | ['Introduction to Data mining', 'CSE5317', 82 | ], 83 | ['Introduction to NLP', 'CSE5321'], 84 | ['Computer System and security', 'Unkown', 85 | ], 86 | ['Programming languages', 'CSE4202'], 87 | ['Project Management', 'CSE4302'], 88 | ['Introduction to Law', 'Unknown'], 89 | ['Compiler Design', 'CSE4310'], 90 | ['Digital Signal Processing', 'ECE3205', 91 | ], 92 | ['VLSI Design', 'ECE5307'], 93 | ['Electrical Network Analysis and synthesis', 'PCE3201', 94 | ], 95 | ['Introduction to Computer Vision', 'CSE4312', 96 | ], 97 | ['Semester Project', 'CSE5201'], 98 | ['Seminar', 'CSE5205'], 99 | ['Distributed Systems', 'CSE5307'], 100 | ['Wireless mobile Networks', 'CSE5309', 101 | ], 102 | ['Image Processing', 'CSE5311'], 103 | ['Human Computer Interaction', 'CSE5313', 104 | ], 105 | ['Introduction to Audio & Video Production', 'CSE5315', 106 | ], 107 | ['Advanced Network', 'CSE5319'], 108 | ['Introduction to Control Systems', 'PCE3204', 109 | ], 110 | ['B.Sc. Project', 'CSE5202'], 111 | ['Entrepreneurship for Engineers', 'SOSC412', ], 112 | ['Computer Games & Animation', 'CSE5304', 113 | ], 114 | ['Special Topics in Computer Science & Engineering', 'CSE5306', 115 | ], 116 | ['Real time and Embedded Systems', 'CSE5308', 117 | ], 118 | ['Software Quality & Testing', 'CSE5310', 119 | ], 120 | ['Computer Ethics and Social Issues', 'CSE5312', 121 | ], 122 | ['Introduction to Robotics and Industrial Automation', 'PCE5308', 123 | ]] 124 | 125 | 126 | @dp.inline_handler() 127 | async def inline_starter(inline_handler: InlineQuery): 128 | """handling the inline searching mode and giving 129 | filtered list of items for the user according 130 | to their text input""" 131 | 132 | item = [] 133 | txt = inline_handler.query or None 134 | if txt is None: 135 | item.append( 136 | InlineQueryResultArticle( 137 | id=str(uuid.uuid4()), 138 | title="Start Typing course name or course code", 139 | description="No result", 140 | input_message_content=InputTextMessageContent("No result") 141 | ) 142 | ) 143 | else: 144 | i = 0 145 | cs = CsFile().get() 146 | for x in lst: 147 | if i >= 30: 148 | break 149 | i += 1 150 | for val in range(2): 151 | if re.search(txt.lower(), x[val].lower()): 152 | Doc_text = f'➖➖ Course Outline ➖➖\n\nName: {x[0]}' \ 153 | f'\nCode: {x[1]}\n\n📚Find More from : @ASTU_COBOT' 154 | item.append( 155 | InlineQueryResultCachedDocument( 156 | id=str(uuid.uuid4()), 157 | title=x[0], 158 | document_file_id=cs[x[1].upper()]['file_id'], 159 | caption=Doc_text, 160 | description=x[1], 161 | parse_mode="HTML" 162 | ) 163 | ) 164 | if len(item) == 0: 165 | item.append( 166 | InlineQueryResultArticle( 167 | id=str(uuid.uuid4()), 168 | title="Oops your search didn't match my course list", 169 | description="No result", 170 | input_message_content=InputTextMessageContent("No result") 171 | ) 172 | ) 173 | await bot.answer_inline_query(inline_handler.id, results=item, cache_time=1) 174 | -------------------------------------------------------------------------------- /Bot/plugins/UserCallbackHandler.py: -------------------------------------------------------------------------------- 1 | from Bot import bot, dp 2 | from aiogram import types 3 | from aiogram.dispatcher.filters import Text 4 | from Bot.helpers import courses, materials, strings, buttons 5 | from Bot.helpers.Database import Users, CsFile 6 | 7 | dataBase = Users() 8 | 9 | 10 | @dp.callback_query_handler(Text(equals="course_menu")) 11 | async def courseS(query: types.CallbackQuery): 12 | """handling the course main menu inline button and giving the 13 | list of collages available""" 14 | 15 | userId = query.from_user.id 16 | lang = dataBase.get_user_lang(userId) 17 | func = courses.collage(lang) 18 | await query.message.edit_text(func[0], reply_markup=func[1]) 19 | 20 | 21 | @dp.callback_query_handler(Text(startswith="material")) 22 | async def materialHandlerInline(query: types.CallbackQuery): 23 | code = query.data.split("_")[1] 24 | func = materials.listMaterials(code) 25 | await query.message.answer(func[0], reply_markup=func[1], parse_mode="HTML") 26 | 27 | 28 | @dp.callback_query_handler(Text(startswith="outline")) 29 | async def materialHandlerInline(query: types.CallbackQuery): 30 | cCode = query.data.split("_")[1] 31 | fullCourse = CsFile().get()[cCode] 32 | 33 | Doc_Text = f'➖➖ Course Outline ➖➖\n\nName: {fullCourse["name"]}' \ 34 | f'\nCode: {fullCourse["code"]}\n\n📚Find More from : @ASTU_COBOT' 35 | try: 36 | await bot.send_document(query.from_user.id, 37 | document=fullCourse['file_id'], 38 | caption=Doc_Text, 39 | parse_mode="HTML") 40 | except: 41 | await query.message.answer( 42 | "Sorry😔\n\nCourse Outline for this course is not available right now.") 43 | 44 | 45 | @dp.callback_query_handler(Text(startswith="exams")) 46 | async def exams_handler(query: types.CallbackQuery): 47 | await query.answer("This feature will be added soon😃", show_alert=True) 48 | 49 | 50 | @dp.callback_query_handler(Text(startswith="displayMaterial")) 51 | async def displayMaterial(query: types.CallbackQuery): 52 | path = query.data.split('_') 53 | mat = CsFile().get()[path[1]]['materials'][int(path[2])] 54 | TEXT = f"*Book Name* : _{mat[0]}_\n\n📚Find More materials : @ASTU\_COBOT" 55 | await bot.send_document(query.from_user.id, 56 | document=mat[1], 57 | caption=TEXT, parse_mode="MARKDOWN") 58 | 59 | 60 | @dp.callback_query_handler(Text(startswith="pageBar")) 61 | async def Pagination(query: types.CallbackQuery): 62 | await query.message.delete() 63 | userId = query.from_user.id 64 | lang = dataBase.get_user_lang(userId) 65 | page = query.data.split("_") 66 | if query.data.startswith("pageBar_back"): 67 | func = materials.materials(start=int(page[2]), end=int(page[3]), i=int(page[4]), lang=lang) 68 | await query.message.answer(func[0], reply_markup=func[1], parse_mode="MARKDOWN") 69 | if query.data.startswith("pageBar_next"): 70 | func = materials.materials(start=int(page[2]), end=int(page[3]), i=int(page[4]), lang=lang) 71 | await query.message.answer(func[0], reply_markup=func[1], parse_mode="MARKDOWN") 72 | 73 | 74 | @dp.callback_query_handler(Text(startswith="listMaterial_")) 75 | async def Pagination(query: types.CallbackQuery): 76 | userId = query.from_user.id 77 | lang = dataBase.get_user_lang(userId) 78 | page = query.data.split("_") 79 | if query.data.startswith("listMaterial_back"): 80 | func = materials.listMaterials(start=int(page[2]), end=int(page[3]), i=int(page[4]), lang=lang, code=page[5]) 81 | await query.message.edit_text(func[0], reply_markup=func[1], parse_mode="HTML") 82 | if query.data.startswith("listMaterial_next"): 83 | func = materials.listMaterials(start=int(page[2]), end=int(page[3]), i=int(page[4]), lang=lang, code=page[5]) 84 | await query.message.edit_text(func[0], reply_markup=func[1], parse_mode="HTML") 85 | 86 | 87 | @dp.callback_query_handler(Text(startswith="lang_")) 88 | async def setLang(query: types.CallbackQuery): 89 | """handling and updating the language by users selection""" 90 | 91 | await query.message.delete() 92 | userId = query.from_user.id 93 | if query.data == "lang_english": 94 | dataBase.set_user_language(userId, 0) 95 | await query.message.answer("Language settled to english", 96 | reply_markup=buttons.menu(userId)) 97 | if query.data == "lang_amharic": 98 | dataBase.set_user_language(userId, 1) 99 | await query.message.answer("ቋንቋ ወደ አማርኛ ተለውጧል", 100 | reply_markup=buttons.menu(userId, 1)) 101 | 102 | 103 | @dp.callback_query_handler(Text(startswith="help_")) 104 | async def helpHandler(query: types.CallbackQuery): 105 | """handling the help desk and giving help to users""" 106 | 107 | userId = query.from_user.id 108 | lang = dataBase.get_user_lang(userId) 109 | if query.data == "help_bot": 110 | await query.message.answer(strings.aboutBot[lang]) 111 | if query.data == "help_admin": 112 | await query.message.answer(strings.helpAdminText[lang]) 113 | if query.data == "help_number": 114 | await query.message.answer(strings.helpNumberText[lang], parse_mode="MARKDOWN") 115 | 116 | 117 | ##################################################################################### 118 | """ COURSE LISTING SECTION """ 119 | 120 | 121 | ##################################################################################### 122 | 123 | 124 | @dp.callback_query_handler(Text(startswith="collage_")) 125 | async def divisionHandler(query: types.CallbackQuery): 126 | userId = query.from_user.id 127 | lang = dataBase.get_user_lang(userId) 128 | sc = query.data.split("_")[1] 129 | func = courses.schools(sc, lang) 130 | await query.message.edit_text(func[0], reply_markup=func[1]) 131 | 132 | 133 | @dp.callback_query_handler(Text(startswith="school_")) 134 | async def schoolHandler(query: types.CallbackQuery): 135 | userId = query.from_user.id 136 | lang = dataBase.get_user_lang(userId) 137 | sc = query.data.split("_") 138 | func = courses.division([sc[1], sc[2]], lang) 139 | await query.message.edit_text(func[0], reply_markup=func[1]) 140 | 141 | 142 | @dp.callback_query_handler(Text(startswith="depart_")) 143 | async def depHandler(query: types.CallbackQuery): 144 | userId = query.from_user.id 145 | lang = dataBase.get_user_lang(userId) 146 | sc = query.data.split("_") 147 | func = courses.department([sc[1], sc[2], sc[3]], lang) 148 | await query.message.edit_text(func[0], reply_markup=func[1]) 149 | 150 | 151 | @dp.callback_query_handler(Text(startswith="year_")) 152 | async def yearHandler(query: types.CallbackQuery): 153 | userId = query.from_user.id 154 | lang = dataBase.get_user_lang(userId) 155 | sc = query.data.split("_") 156 | func = courses.year([sc[1], sc[2], sc[3], sc[4]], lang) 157 | await query.message.edit_text(func[0], reply_markup=func[1]) 158 | 159 | 160 | @dp.callback_query_handler(Text(startswith="semester_")) 161 | async def semesterHandler(query: types.CallbackQuery): 162 | userId = query.from_user.id 163 | lang = dataBase.get_user_lang(userId) 164 | sc = query.data.split("_") 165 | func = courses.semester([sc[1], sc[2], sc[3], sc[4], sc[5]], lang=lang) 166 | await query.message.edit_text(func[0], reply_markup=func[1]) 167 | -------------------------------------------------------------------------------- /Bot/plugins/StateHandler.py: -------------------------------------------------------------------------------- 1 | ##################################################################################### 2 | """ HANDLING STATES """ 3 | ##################################################################################### 4 | from Bot import dp 5 | from Bot.helpers import ManageCourse 6 | from Bot.helpers.BotStatus import adminLog 7 | from Bot.helpers.Database import CsFile 8 | from aiogram import types 9 | from Bot.helpers.buttons import cancelBtn, menu 10 | from aiogram.dispatcher import FSMContext 11 | from Bot.helpers.ManageCourse import AddMaterialForm, RemoveMaterialForm, DescEditForm, CourseManager, CrhEditForm, \ 12 | FileIdEditForm, AddNewCourseForm 13 | 14 | 15 | @dp.message_handler(state=DescEditForm.code) 16 | async def editDesc(message: types.Message, state: FSMContext): 17 | if message.text == '🚫Cancel': 18 | await message.answer("Process cancelled") 19 | await state.finish() 20 | elif message.text in list(CsFile().get()): 21 | async with state.proxy() as data: 22 | data['code'] = message.text 23 | await message.answer("Now send me the description for this course", reply_markup=cancelBtn) 24 | await DescEditForm.next() 25 | else: 26 | await message.answer("The course code you entered is incorrect") 27 | 28 | 29 | @dp.message_handler(state=DescEditForm.desc) 30 | async def editDesc(message: types.Message, state: FSMContext): 31 | if message.text == '🚫Cancel': 32 | await message.answer("Process cancelled", reply_markup=menu(message.from_user.id)) 33 | await state.finish() 34 | else: 35 | async with state.proxy() as data: 36 | cs = CourseManager() 37 | cs.edit_desc(c_code=data['code'], value=message.text) 38 | stat = f"Changed course description of {data['code']} to \n{message.text}" 39 | await adminLog(message, stat) 40 | await message.answer("Description changed successfully", reply_markup=menu(message.from_user.id)) 41 | await state.finish() 42 | 43 | 44 | ######################################################################################### 45 | 46 | 47 | @dp.message_handler(state=CrhEditForm.code) 48 | async def editDesc(message: types.Message, state: FSMContext): 49 | if message.text == '🚫Cancel': 50 | await message.answer("Process cancelled", reply_markup=menu(message.from_user.id)) 51 | await state.finish() 52 | elif message.text in list(CsFile().get()): 53 | async with state.proxy() as data: 54 | data['code'] = message.text 55 | await message.answer("Now send me the Credit hour for this course", reply_markup=cancelBtn) 56 | await CrhEditForm.next() 57 | else: 58 | await message.answer("The course code you entered is incorrect") 59 | 60 | 61 | @dp.message_handler(state=CrhEditForm.crh) 62 | async def editDesc(message: types.Message, state: FSMContext): 63 | if message.text == '🚫Cancel': 64 | await message.answer("Process cancelled", reply_markup=menu(message.from_user.id)) 65 | await state.finish() 66 | else: 67 | async with state.proxy() as data: 68 | cs = CourseManager() 69 | cs.edit_crh(c_code=data['code'], value=message.text) 70 | await message.answer("Credit hour changed successfully", reply_markup=menu(message.from_user.id)) 71 | stat = f'Changed course chr for {data["code"]} to {message.text}' 72 | await adminLog(message, stat) 73 | await state.finish() 74 | 75 | 76 | ######################################################################################### 77 | 78 | 79 | @dp.message_handler(state=FileIdEditForm.code) 80 | async def editDesc(message: types.Message, state: FSMContext): 81 | if message.text == '🚫Cancel': 82 | await message.answer("Process cancelled", reply_markup=menu(message.from_user.id)) 83 | await state.finish() 84 | elif message.text in list(CsFile().get()): 85 | async with state.proxy() as data: 86 | data['code'] = message.text 87 | await message.answer("Now send me the File for this course", reply_markup=cancelBtn) 88 | await FileIdEditForm.next() 89 | else: 90 | await message.answer("The course code you entered is incorrect") 91 | 92 | 93 | @dp.message_handler(state=FileIdEditForm.file, content_types=types.message.ContentType.ANY) 94 | async def editDesc(message: types.message.ContentType.ANY, state: FSMContext): 95 | if message.text == '🚫Cancel': 96 | await message.answer("Process cancelled", reply_markup=menu(message.from_user.id)) 97 | await state.finish() 98 | elif message.document: 99 | async with state.proxy() as data: 100 | cs = CourseManager() 101 | cs.edit_fileId(c_code=data['code'], value=message.document.file_id) 102 | await message.answer("File changed successfully", reply_markup=menu(message.from_user.id)) 103 | stat = f'Changed course File for {data["code"]} to {message.document.file_id}' 104 | await adminLog(message, stat) 105 | await state.finish() 106 | else: 107 | await message.answer("Please send me document file.", reply_markup=cancelBtn) 108 | 109 | #################################################################################### 110 | 111 | 112 | @dp.message_handler(state=RemoveMaterialForm.code) 113 | async def removeMaterial(message: types.Message, state: FSMContext): 114 | if message.text == '🚫Cancel': 115 | await message.answer("Process cancelled", reply_markup=menu(message.from_user.id)) 116 | await state.finish() 117 | elif message.text in list(CsFile().get()): 118 | func = ManageCourse.listMaterials(message.text) 119 | await message.answer(func[0], reply_markup=func[1], parse_mode="MARKDOWN") 120 | await state.finish() 121 | else: 122 | await message.answer("The course code you entered is incorrect", reply_markup=cancelBtn) 123 | 124 | ##################################################################################### 125 | 126 | 127 | @dp.message_handler(state=AddMaterialForm.code) 128 | async def removeMaterial(message: types.Message, state: FSMContext): 129 | if message.text == '🚫Cancel': 130 | await message.answer("Process cancelled", reply_markup=menu(message.from_user.id)) 131 | await state.finish() 132 | elif message.text in list(CsFile().get()): 133 | async with state.proxy() as data: 134 | data['code'] = message.text 135 | await message.answer("Send me Course Title/Name", reply_markup=cancelBtn) 136 | await AddMaterialForm.next() 137 | else: 138 | await message.answer("The course code you entered is incorrect") 139 | 140 | 141 | @dp.message_handler(state=AddMaterialForm.cName) 142 | async def removeMaterial(message: types.Message, state: FSMContext): 143 | if message.text == '🚫Cancel': 144 | await message.answer("Process cancelled", reply_markup=menu(message.from_user.id)) 145 | await state.finish() 146 | else: 147 | async with state.proxy() as data: 148 | data['name'] = message.text 149 | await message.answer("Please send material\'s Document/File", reply_markup=cancelBtn) 150 | await AddMaterialForm.next() 151 | 152 | 153 | @dp.message_handler(state=AddMaterialForm.cFile, content_types=types.message.ContentType.ANY) 154 | async def AddMatCFile(message: types.Message, state: FSMContext): 155 | if message.text == '🚫Cancel': 156 | await message.answer("Process cancelled", reply_markup=menu(message.from_user.id)) 157 | await state.finish() 158 | elif message.document: 159 | async with state.proxy() as data: 160 | data['fileId'] = message.document.file_id 161 | NewMaterial = [data['name'], data['fileId']] 162 | CourseManager().add_material(data['code'], NewMaterial) 163 | await message.answer("Material Added Successfully!", reply_markup=menu(message.from_user.id)) 164 | stat = f'Added material for {data["code"]} \nNamed: {data["name"]}' 165 | await adminLog(message, stat) 166 | await state.finish() 167 | else: 168 | await message.answer("🙂Incorrect Document\nPlease send material\'s Document/File", reply_markup=cancelBtn) 169 | 170 | 171 | @dp.message_handler(state=AddNewCourseForm.code) 172 | async def removeMaterial(message: types.Message, state: FSMContext): 173 | if message.text == '🚫Cancel': 174 | await message.answer("Process cancelled", reply_markup=menu(message.from_user.id)) 175 | await state.finish() 176 | elif message.text not in list(CsFile().get()): 177 | async with state.proxy() as data: 178 | data['code'] = message.text 179 | await message.answer("Send me Course Title/Name", reply_markup=cancelBtn) 180 | await AddNewCourseForm.next() 181 | else: 182 | await message.answer("The course code you entered is available in the courses list") 183 | 184 | 185 | @dp.message_handler(state=AddNewCourseForm.name) 186 | async def removeMaterial(message: types.Message, state: FSMContext): 187 | if message.text == '🚫Cancel': 188 | await message.answer("Process cancelled", reply_markup=menu(message.from_user.id)) 189 | await state.finish() 190 | else: 191 | async with state.proxy() as data: 192 | data['name'] = message.text 193 | cs = CourseManager() 194 | cs.add_course(code=data['code'].upper(), name=message.text) 195 | await message.answer("Course added successfully go and edit details about it.", 196 | reply_markup=menu(message.from_user.id)) 197 | stat = f'Added new course {data["code"]}' 198 | await adminLog(message, stat) 199 | await state.finish() 200 | -------------------------------------------------------------------------------- /Bot/helpers/courses.json: -------------------------------------------------------------------------------- 1 | { 2 | "Engineering": { 3 | "Freshman Division": { 4 | "1st Semester": [ 5 | ["Applied Mathematics I", "Math1101"], 6 | ["General Physics-I", "Phys1101"], 7 | ["General Chemistry", "Chem1101"], 8 | ["Introduction to Computing", "CSE1101"], 9 | ["Communicative English Skills", "ENG1011"], 10 | ["Civic and Ethical Education", "LAR1011"], 11 | ["Health &Physical Education I", "HPEd1011"], 12 | ["Logic and Critical Thinking", "LAR1012"] 13 | ], 14 | "2nd Semester": [ 15 | ["Applied Mathematics II", "Math1102"], 16 | ["Emerging Technologies", "Phys1102"], 17 | ["Fundamentals of Programming", "CSE1102"], 18 | ["Engineering Drawing", "DME1102"], 19 | ["Basic Writing Skills", "ENG1102"], 20 | ["Health &Physical Education I", "HPEd1012"], 21 | ["Logic and Critical Thinking", "LAR1012"], 22 | ["Civic and Ethical Education", "LAR1011"] 23 | ] 24 | }, 25 | "SoEEC": { 26 | "2nd Year 1st Semester": [ 27 | ["Data Structure and Algorithm", "CSE2101"], 28 | ["Electronic Circuit", "ECE2101"], 29 | ["Applied Mathematics III", "MATH2051"], 30 | ["Fundamental of Electrical Engineering", "PCE2101"], 31 | ["Geography of Ethiopia and the Horn", "LART1004"] 32 | ], 33 | "CSE": { 34 | "2nd Year": { 35 | "2nd Semester": [ 36 | ["Object Oriented Programming", "CSE2202"], 37 | ["Discrete Mathematics for CSE", "CSE2206"], 38 | ["Digital Logic Design", "ECE3204"], 39 | ["Database Systems", "CSE3207"], 40 | ["Electronic circuit II", "ECE2202"], 41 | ["System Programming", "CSE2320"], 42 | ["Computer Graphics", "CSE3310"] 43 | ] 44 | }, 45 | "3rd Year": { 46 | "1st Semester": [ 47 | ["Algorithms", "CSE3211"], 48 | ["Probability and Random Process", "ECE3103"], 49 | ["Fund. of software Engineering", "CSE3205"], 50 | ["Computer Architecture & Organization", "CSE3203"] 51 | ], 52 | "2nd Semester": [ 53 | ["Operating System", "CSE3204"], 54 | ["Data Communication & Computer Networks", "CSE3221"], 55 | ["Introduction to Artificial", "CSE3206"], 56 | ["Software Requirement Engineering", "CSE3308"], 57 | ["Web Programming", "CSE3306"], 58 | ["Advanced Programming", "CSE3312"] 59 | ] 60 | }, 61 | "4th Year": { 62 | "1st Semester": [ 63 | ["Formal Language and automata Theory", "Unknown"], 64 | ["Engineering Research and Development Methodology", "CSE4221"], 65 | ["Multimedia Tech.", "CSE4303"], 66 | ["Software Design and Architecture", "CSE4309"], 67 | ["Mobile Computing and Applications", "CSE4311"], 68 | ["Signals and Systems", "ECE2204"], 69 | ["Introduction to Data mining", "CSE5317"], 70 | ["Introduction to NLP", "CSE5321"], 71 | ["Computer System and security", "Unknown"] 72 | ], 73 | "2nd Semester": [ 74 | ["Programming languages", "CSE4202"], 75 | ["Project Management", "CSE4302"], 76 | ["Introduction to Law", "Unknown"], 77 | ["Compiler Design", "CSE4310"], 78 | ["Digital Signal Processing", "ECE3205"], 79 | ["VLSI Design", "ECE5307"], 80 | ["Electrical Network Analysis and synthesis", "PCE3201"], 81 | ["Introduction to Computer Vision", "CSE4312"] 82 | ] 83 | }, 84 | "5th Year": { 85 | "1st Semester": [ 86 | ["Semester Project", "CSE5201"], 87 | ["Seminar", "CSE5205"], 88 | ["Distributed Systems", "CSE5307"], 89 | ["Wireless mobile Networks", "CSE5309"], 90 | ["Image Processing", "CSE5311"], 91 | ["Human Computer Interaction", "CSE5313"], 92 | ["Introduction to Audio & Video Production", "CSE5315"], 93 | ["Advanced Network", "CSE5319"], 94 | ["Introduction to Control Systems", "PCE3204"] 95 | ], 96 | "2nd Semester": [ 97 | ["B.Sc. Project", "CSE5202"], 98 | ["Entrepreneurship for Engineers", "SOSC412"], 99 | ["Computer Games & Animation", "CSE5304"], 100 | ["Special Topics in Computer Science & Engineering", "CSE5306"], 101 | ["Real time and Embedded Systems", "CSE5308"], 102 | ["Software Quality & Testing", "CSE5310"], 103 | ["Computer Ethics and Social Issues", "CSE5312"], 104 | ["Introduction to Robotics and Industrial Automation", "PCE5308"] 105 | ] 106 | } 107 | }, 108 | "ECE": { 109 | "2nd Year": { 110 | "2nd Semester": [ 111 | ["None Available", "None"] 112 | ] 113 | }, 114 | "3rd Year": { 115 | "1st Semester": [ 116 | ["None Available", "None"] 117 | ], 118 | "2nd Semester": [ 119 | ["None Available", "None"] 120 | ] 121 | }, 122 | "4th Year": { 123 | "1st Semester": [ 124 | ["None Available", "None"] 125 | ], 126 | "2nd Semester": [ 127 | ["None Available", "None"] 128 | ] 129 | }, 130 | "5th Year": { 131 | "1st Semester": [ 132 | ["None Available", "None"] 133 | ], 134 | "2nd Semester": [ 135 | ["None Available", "None"] 136 | ] 137 | } 138 | 139 | }, 140 | "EPCE": { 141 | "2nd Year": { 142 | "2nd Semester": [ 143 | ["None Available", "None"] 144 | ] 145 | }, 146 | "3rd Year": { 147 | "1st Semester": [ 148 | ["None Available", "None"] 149 | ], 150 | "2nd Semester": [ 151 | ["None Available", "None"] 152 | ] 153 | }, 154 | "4th Year": { 155 | "1st Semester": [ 156 | ["None Available", "None"] 157 | ], 158 | "2nd Semester": [ 159 | ["None Available", "None"] 160 | ] 161 | }, 162 | "5th Year": { 163 | "1st Semester": [ 164 | ["None Available", "None"] 165 | ], 166 | "2nd Semester": [ 167 | ["None Available", "None"] 168 | ] 169 | } 170 | 171 | } 172 | }, 173 | "SoMCME": { 174 | "2nd Year 1st Semester": [ 175 | [ 176 | "Machine Drawing", 177 | "MENG2105" 178 | ], 179 | [ 180 | "Basic Workshop Practice", 181 | "MENG2101" 182 | ], 183 | [ 184 | "Applied Mathematics III", 185 | "MATH2051" 186 | ], 187 | [ 188 | "Introduction to Engineering Materials", 189 | "MSCE2101" 190 | ], 191 | [ 192 | "Engineering Mechanics I (Statics)", 193 | "CENG2201" 194 | ], 195 | [ 196 | "General Psychology and Life skill", 197 | "LART2002" 198 | ] 199 | ], 200 | "Mechanical": { 201 | "2nd Year": { 202 | "2nd Semester": [ 203 | [ 204 | "None Available", 205 | "None" 206 | ] 207 | ] 208 | }, 209 | "3rd Year": { 210 | "1st Semester": [ 211 | [ 212 | "None Available", 213 | "None" 214 | ] 215 | ], 216 | "2nd Semester": [ 217 | [ 218 | "None Available", 219 | "None" 220 | ] 221 | ] 222 | }, 223 | "4th Year": { 224 | "1st Semester": [ 225 | [ 226 | "None Available", 227 | "None" 228 | ] 229 | ], 230 | "2nd Semester": [ 231 | [ 232 | "None Available", 233 | "None" 234 | ] 235 | ] 236 | }, 237 | "5th Year": { 238 | "1st Semester": [ 239 | [ 240 | "None Available", 241 | "None" 242 | ] 243 | ], 244 | "2nd Semester": [ 245 | [ 246 | "None Available", 247 | "None" 248 | ] 249 | ] 250 | } 251 | }, 252 | "Chemical": { 253 | "2nd Year": { 254 | "2nd Semester": [ 255 | [ 256 | "None Available", 257 | "None" 258 | ] 259 | ] 260 | }, 261 | "3rd Year": { 262 | "2nd Semester": [ 263 | [ 264 | "None Available", 265 | "None" 266 | ] 267 | ] 268 | }, 269 | "4th Year": { 270 | "1st Semester": [ 271 | [ 272 | "None Available", 273 | "None" 274 | ] 275 | ], 276 | "2nd Semester": [ 277 | [ 278 | "None Available", 279 | "None" 280 | ] 281 | ] 282 | }, 283 | "5th Year": { 284 | "1st Semester": [ 285 | [ 286 | "None Available", 287 | "None" 288 | ] 289 | ], 290 | "2nd Semester": [ 291 | [ 292 | "None Available", 293 | "None" 294 | ] 295 | ] 296 | } 297 | }, 298 | "Material": { 299 | "2nd Year": { 300 | "2nd Semester": [ 301 | [ 302 | "None Available", 303 | "None" 304 | ] 305 | ] 306 | }, 307 | "3rd Year": { 308 | "1st Semester": [ 309 | [ 310 | "None Available", 311 | "None" 312 | ] 313 | ], 314 | "2nd Semester": [ 315 | [ 316 | "None Available", 317 | "None" 318 | ] 319 | ] 320 | }, 321 | "4th Year": { 322 | "1st Semester": [ 323 | [ 324 | "None Available", 325 | "None" 326 | ] 327 | ], 328 | "2nd Semester": [ 329 | [ 330 | "None Available", 331 | "None" 332 | ] 333 | ] 334 | }, 335 | "5th Year": { 336 | "1st Semester": [ 337 | [ 338 | "None Available", 339 | "None" 340 | ] 341 | ], 342 | "2nd Semester": [ 343 | [ 344 | "None Available", 345 | "None" 346 | ] 347 | ] 348 | } 349 | } 350 | }, 351 | "SoCEA": { 352 | "2nd Year 1st Semester": [ 353 | ["General Psychology and Life skill", "LART2002"], 354 | ["Architectural Working Drawing", "ARCH2201"], 355 | ["Construction Materials", "CENG2205"], 356 | ["Engineering Mechanics", "CENG2201"], 357 | ["Fundamental of surveying", "CENG2203"], 358 | ["Probability and Statics for Engineers", "MATH2105"] 359 | ], 360 | "Architecture": { 361 | "2nd Year": { 362 | "2nd Semester": [ 363 | [ 364 | "None Available", 365 | "None" 366 | ] 367 | ] 368 | }, 369 | "3rd Year": { 370 | "1st Semester": [ 371 | [ 372 | "None Available", 373 | "None" 374 | ] 375 | ], 376 | "2nd Semester": [ 377 | [ 378 | "None Available", 379 | "None" 380 | ] 381 | ] 382 | }, 383 | "4th Year": { 384 | "1st Semester": [ 385 | [ 386 | "None Available", 387 | "None" 388 | ] 389 | ], 390 | "2nd Semester": [ 391 | [ 392 | "None Available", 393 | "None" 394 | ] 395 | ] 396 | }, 397 | "5th Year": { 398 | "1st Semester": [ 399 | [ 400 | "None Available", 401 | "None" 402 | ] 403 | ], 404 | "2nd Semester": [ 405 | [ 406 | "None Available", 407 | "None" 408 | ] 409 | ] 410 | } 411 | }, 412 | "Civil": { 413 | "2nd Year": { 414 | "2nd Semester": [ 415 | [ 416 | "None Available", 417 | "None" 418 | ] 419 | ] 420 | }, 421 | "3rd Year": { 422 | "1st Semester": [ 423 | [ 424 | "None Available", 425 | "None" 426 | ] 427 | ], 428 | "2nd Semester": [ 429 | [ 430 | "None Available", 431 | "None" 432 | ] 433 | ] 434 | }, 435 | "4th Year": { 436 | "1st Semester": [ 437 | [ 438 | "None Available", 439 | "None" 440 | ] 441 | ], 442 | "2nd Semester": [ 443 | [ 444 | "None Available", 445 | "None" 446 | ] 447 | ] 448 | }, 449 | "5th Year": { 450 | "1st Semester": [ 451 | [ 452 | "None Available", 453 | "None" 454 | ] 455 | ], 456 | "2nd Semester": [ 457 | [ 458 | "None Available", 459 | "None" 460 | ] 461 | ] 462 | } 463 | }, 464 | "Water": { 465 | "2nd Year": { 466 | "2nd Semester": [ 467 | [ 468 | "None Available", 469 | "None" 470 | ] 471 | ] 472 | }, 473 | "3rd Year": { 474 | "1st Semester": [ 475 | [ 476 | "None Available", 477 | "None" 478 | ] 479 | ], 480 | "2nd Semester": [ 481 | [ 482 | "None Available", 483 | "None" 484 | ] 485 | ] 486 | }, 487 | "4th Year": { 488 | "1st Semester": [ 489 | [ 490 | "None Available", 491 | "None" 492 | ] 493 | ], 494 | "2nd Semester": [ 495 | [ 496 | "None Available", 497 | "None" 498 | ] 499 | ] 500 | }, 501 | "5th Year": { 502 | "1st Semester": [ 503 | [ 504 | "None Available", 505 | "None" 506 | ] 507 | ], 508 | "2nd Semester": [ 509 | [ 510 | "None Available", 511 | "None" 512 | ] 513 | ] 514 | } 515 | } 516 | } 517 | }, 518 | "Applied": { 519 | "Freshman Division": { 520 | "1st Semester": [ 521 | ["Applied Mathematics I", "Math1101"], 522 | ["General Physics-I", "Phys1101"], 523 | ["General Chemistry", "Chem1101"], 524 | ["Introduction to Computing", "CSE1101"], 525 | ["Communicative English Skills", "ENG1011"], 526 | ["Civic and Ethical Education", "LAR1011"], 527 | ["Health &Physical Education I", "HPEd1011"], 528 | ["Logic and Critical Thinking", "LAR1012"] 529 | ], 530 | "2nd Semester": [ 531 | ["Applied Mathematics II", "Math1102"], 532 | ["Emerging Technologies", "Phys1102"], 533 | ["Fundamentals of Programming", "CSE1102"], 534 | ["Engineering Drawing", "DME1102"], 535 | ["Basic Writing Skills", "ENG1102"], 536 | ["Health &Physical Education I", "HPEd1012"], 537 | ["Logic and Critical Thinking", "LAR1012"], 538 | ["Civic and Ethical Education", "LAR1011"] 539 | ] 540 | }, 541 | "Applied Physics": { 542 | "2nd Year": { 543 | "1st Semester": [ 544 | [ 545 | "None Available", 546 | "None" 547 | ] 548 | ], 549 | "2nd Semester": [ 550 | [ 551 | "None Available", 552 | "None" 553 | ] 554 | ] 555 | }, 556 | "3rd Year": { 557 | "1st Semester": [ 558 | [ 559 | "None Available", 560 | "None" 561 | ] 562 | ], 563 | "2nd Semester": [ 564 | [ 565 | "None Available", 566 | "None" 567 | ] 568 | ] 569 | }, 570 | "4th Year": { 571 | "1st Semester": [ 572 | [ 573 | "None Available", 574 | "None" 575 | ] 576 | ], 577 | "2nd Semester": [ 578 | [ 579 | "None Available", 580 | "None" 581 | ] 582 | ] 583 | }, 584 | "5th Year": { 585 | "1st Semester": [ 586 | [ 587 | "None Available", 588 | "None" 589 | ] 590 | ], 591 | "2nd Semester": [ 592 | [ 593 | "None Available", 594 | "None" 595 | ] 596 | ] 597 | } 598 | }, 599 | "Applied Biology": { 600 | "2nd Year": { 601 | "1st Semester": [ 602 | [ 603 | "None Available", 604 | "None" 605 | ] 606 | ], 607 | "2nd Semester": [ 608 | [ 609 | "None Available", 610 | "None" 611 | ] 612 | ] 613 | }, 614 | "3rd Year": { 615 | "1st Semester": [ 616 | [ 617 | "None Available", 618 | "None" 619 | ] 620 | ], 621 | "2nd Semester": [ 622 | [ 623 | "None Available", 624 | "None" 625 | ] 626 | ] 627 | }, 628 | "4th Year": { 629 | "1st Semester": [ 630 | [ 631 | "None Available", 632 | "None" 633 | ] 634 | ], 635 | "2nd Semester": [ 636 | [ 637 | "None Available", 638 | "None" 639 | ] 640 | ] 641 | }, 642 | "5th Year": { 643 | "1st Semester": [ 644 | [ 645 | "None Available", 646 | "None" 647 | ] 648 | ], 649 | "2nd Semester": [ 650 | [ 651 | "None Available", 652 | "None" 653 | ] 654 | ] 655 | } 656 | }, 657 | "Applied Chemistry": { 658 | "2nd Year": { 659 | "1st Semester": [ 660 | [ 661 | "None Available", 662 | "None" 663 | ] 664 | ], 665 | "2nd Semester": [ 666 | [ 667 | "None Available", 668 | "None" 669 | ] 670 | ] 671 | }, 672 | "3rd Year": { 673 | "1st Semester": [ 674 | [ 675 | "None Available", 676 | "None" 677 | ] 678 | ], 679 | "2nd Semester": [ 680 | [ 681 | "None Available", 682 | "None" 683 | ] 684 | ] 685 | }, 686 | "4th Year": { 687 | "1st Semester": [ 688 | [ 689 | "None Available", 690 | "None" 691 | ] 692 | ], 693 | "2nd Semester": [ 694 | [ 695 | "None Available", 696 | "None" 697 | ] 698 | ] 699 | }, 700 | "5th Year": { 701 | "1st Semester": [ 702 | [ 703 | "None Available", 704 | "None" 705 | ] 706 | ], 707 | "2nd Semester": [ 708 | [ 709 | "None Available", 710 | "None" 711 | ] 712 | ] 713 | } 714 | }, 715 | "Applied Geology": { 716 | "2nd Year": { 717 | "1st Semester": [ 718 | [ 719 | "None Available", 720 | "None" 721 | ] 722 | ], 723 | "2nd Semester": [ 724 | [ 725 | "None Available", 726 | "None" 727 | ] 728 | ] 729 | }, 730 | "3rd Year": { 731 | "1st Semester": [ 732 | [ 733 | "None Available", 734 | "None" 735 | ] 736 | ], 737 | "2nd Semester": [ 738 | [ 739 | "None Available", 740 | "None" 741 | ] 742 | ] 743 | }, 744 | "4th Year": { 745 | "1st Semester": [ 746 | [ 747 | "None Available", 748 | "None" 749 | ] 750 | ], 751 | "2nd Semester": [ 752 | [ 753 | "None Available", 754 | "None" 755 | ] 756 | ] 757 | }, 758 | "5th Year": { 759 | "1st Semester": [ 760 | [ 761 | "None Available", 762 | "None" 763 | ] 764 | ], 765 | "2nd Semester": [ 766 | [ 767 | "None Available", 768 | "None" 769 | ] 770 | ] 771 | } 772 | }, 773 | "Applied Mathematics": { 774 | "2nd Year": { 775 | "1st Semester": [ 776 | [ 777 | "None Available", 778 | "None" 779 | ] 780 | ], 781 | "2nd Semester": [ 782 | [ 783 | "None Available", 784 | "None" 785 | ] 786 | ] 787 | }, 788 | "3rd Year": { 789 | "1st Semester": [ 790 | [ 791 | "None Available", 792 | "None" 793 | ] 794 | ], 795 | "2nd Semester": [ 796 | [ 797 | "None Available", 798 | "None" 799 | ] 800 | ] 801 | }, 802 | "4th Year": { 803 | "1st Semester": [ 804 | [ 805 | "None Available", 806 | "None" 807 | ] 808 | ], 809 | "2nd Semester": [ 810 | [ 811 | "None Available", 812 | "None" 813 | ] 814 | ] 815 | }, 816 | "5th Year": { 817 | "1st Semester": [ 818 | [ 819 | "None Available", 820 | "None" 821 | ] 822 | ], 823 | "2nd Semester": [ 824 | [ 825 | "None Available", 826 | "None" 827 | ] 828 | ] 829 | } 830 | } 831 | 832 | } 833 | } -------------------------------------------------------------------------------- /Bot/helpers/course_set.json: -------------------------------------------------------------------------------- 1 | { 2 | "MATH1101": { 3 | "name": "Applied Mathematics I", 4 | "code": "Math1101", 5 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 6 | "crh": "3", 7 | "description": "None available", 8 | "exams": [ 9 | [ 10 | "2018 Mid Exam", 11 | 1 12 | ], 13 | [ 14 | "2018 Mid Exam", 15 | 2 16 | ], 17 | [ 18 | "2018 Mid Exam", 19 | 3 20 | ] 21 | ], 22 | "materials": [ 23 | [ 24 | "Applied Begashaw", 25 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 26 | ], 27 | [ 28 | "University Mathematics", 29 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 30 | ], 31 | [ 32 | "Maths for Dummies", 33 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 34 | ], 35 | [ 36 | "Calculus 1", 37 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 38 | ], 39 | [ 40 | "Think Maths", 41 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 42 | ], 43 | [ 44 | "More book", 45 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 46 | ], 47 | [ 48 | "More book", 49 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 50 | ], 51 | [ 52 | "More book", 53 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 54 | ], 55 | [ 56 | "More book", 57 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 58 | ], 59 | [ 60 | "More book", 61 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 62 | ], 63 | [ 64 | "More book", 65 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 66 | ], 67 | [ 68 | "More book", 69 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 70 | ], 71 | [ 72 | "Applied Begashaw", 73 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 74 | ], 75 | [ 76 | "Applied Begashaw", 77 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 78 | ], 79 | [ 80 | "Applied Begashaw", 81 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 82 | ], 83 | [ 84 | "University Mathematics", 85 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 86 | ], 87 | [ 88 | "Maths for Dummies", 89 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 90 | ], 91 | [ 92 | "Calculus 1", 93 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 94 | ], 95 | [ 96 | "Think Maths", 97 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 98 | ], 99 | [ 100 | "More book", 101 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 102 | ], 103 | [ 104 | "Applied Begashaw", 105 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 106 | ], 107 | [ 108 | "University Mathematics", 109 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 110 | ], 111 | [ 112 | "Maths for Dummies", 113 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 114 | ], 115 | [ 116 | "Calculus 1", 117 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 118 | ], 119 | [ 120 | "Think Maths", 121 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 122 | ], 123 | [ 124 | "More book", 125 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 126 | ], 127 | [ 128 | "More book", 129 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 130 | ], 131 | [ 132 | "More book", 133 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 134 | ], 135 | [ 136 | "More book", 137 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 138 | ], 139 | [ 140 | "More book", 141 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 142 | ], 143 | [ 144 | "More book", 145 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 146 | ], 147 | [ 148 | "More book", 149 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 150 | ], 151 | [ 152 | "Applied Begashaw", 153 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 154 | ], 155 | [ 156 | "Applied Begashaw", 157 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 158 | ], 159 | [ 160 | "Applied Begashaw", 161 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 162 | ], 163 | [ 164 | "University Mathematics", 165 | "BQACAgQAAxkBAAENf4Fh4xoe5J0Qq2pEC6odSg-gap8O4AACpAsAAiNKSFB0m7hNLKOQvSME" 166 | ] 167 | ] 168 | }, 169 | "PHYS1101": { 170 | "name": "General Physics-I", 171 | "code": "Phys1101", 172 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 173 | "crh": "3", 174 | "description": "None available", 175 | "materials": [ 176 | [ 177 | "Test File", 178 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 179 | ] 180 | ] 181 | }, 182 | "CHEM1101": { 183 | "name": "General Chemistry", 184 | "code": "Chem1101", 185 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 186 | "crh": "3", 187 | "description": "None available", 188 | "materials": [ 189 | [ 190 | "Test File", 191 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 192 | ] 193 | ] 194 | }, 195 | "CSE1101": { 196 | "name": "Introduction to Computing", 197 | "code": "CSE1101", 198 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 199 | "crh": "3", 200 | "description": "None available", 201 | "materials": [ 202 | [ 203 | "Test File", 204 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 205 | ] 206 | ] 207 | }, 208 | "ENG1011": { 209 | "name": "Communicative English Skills", 210 | "code": "ENG1011", 211 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 212 | "crh": "3", 213 | "description": "None available", 214 | "materials": [ 215 | [ 216 | "Test File", 217 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 218 | ] 219 | ] 220 | }, 221 | "LAR1011": { 222 | "name": "Civic and Ethical Education", 223 | "code": "LAR1011", 224 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 225 | "crh": "3", 226 | "description": "None available", 227 | "materials": [ 228 | [ 229 | "Test File", 230 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 231 | ] 232 | ] 233 | }, 234 | "HPED1011": { 235 | "name": "Health &Physical Education I", 236 | "code": "HPEd1011", 237 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 238 | "crh": "3", 239 | "description": "None available", 240 | "materials": [ 241 | [ 242 | "Test File", 243 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 244 | ] 245 | ] 246 | }, 247 | "LAR1012": { 248 | "name": "Logic and Critical Thinking", 249 | "code": "LAR1012", 250 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 251 | "crh": "3", 252 | "description": "None available", 253 | "materials": [ 254 | [ 255 | "Test File", 256 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 257 | ] 258 | ] 259 | }, 260 | "MATH1102": { 261 | "name": "Applied Mathematics II", 262 | "code": "Math1102", 263 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 264 | "crh": "3", 265 | "description": "None available", 266 | "materials": [ 267 | [ 268 | "Test File", 269 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 270 | ] 271 | ] 272 | }, 273 | "PHYS1102": { 274 | "name": "Emerging Technologies", 275 | "code": "Phys1102", 276 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 277 | "crh": "3", 278 | "description": "None available", 279 | "materials": [ 280 | [ 281 | "Test File", 282 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 283 | ] 284 | ] 285 | }, 286 | "CSE1102": { 287 | "name": "Fundamentals of Programming", 288 | "code": "CSE1102", 289 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 290 | "crh": "3", 291 | "description": "None available", 292 | "materials": [ 293 | [ 294 | "Test File", 295 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 296 | ] 297 | ] 298 | }, 299 | "DME1102": { 300 | "name": "Engineering Drawing", 301 | "code": "DME1102", 302 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 303 | "crh": "3", 304 | "description": "None available", 305 | "materials": [ 306 | [ 307 | "Test File", 308 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 309 | ] 310 | ] 311 | }, 312 | "ENG1102": { 313 | "name": "Basic Writing Skills", 314 | "code": "ENG1102", 315 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 316 | "crh": "3", 317 | "description": "None available", 318 | "materials": [ 319 | [ 320 | "Test File", 321 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 322 | ] 323 | ] 324 | }, 325 | "CSE2101": { 326 | "name": "Data Structure and Algorithm", 327 | "code": "CSE2101", 328 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 329 | "crh": "3", 330 | "description": "None available", 331 | "materials": [ 332 | [ 333 | "Test File", 334 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 335 | ] 336 | ] 337 | }, 338 | "ECE2101": { 339 | "name": "Electronic Circuit", 340 | "code": "ECE2101", 341 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 342 | "crh": "3", 343 | "description": "None available", 344 | "materials": [ 345 | [ 346 | "Test File", 347 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 348 | ] 349 | ] 350 | }, 351 | "MATH2051": { 352 | "name": "Applied Mathematics III", 353 | "code": "MATH2051", 354 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 355 | "crh": "3", 356 | "description": "None available", 357 | "materials": [ 358 | [ 359 | "Test File", 360 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 361 | ] 362 | ] 363 | }, 364 | "PCE2101": { 365 | "name": "Fundamental of Electrical Engineering", 366 | "code": "PCE2101", 367 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 368 | "crh": "3", 369 | "description": "None available", 370 | "materials": [ 371 | [ 372 | "Test File", 373 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 374 | ] 375 | ] 376 | }, 377 | "SOS311": { 378 | "name": "Principle of Economics", 379 | "code": "SOS311", 380 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 381 | "crh": "3", 382 | "description": "None available", 383 | "materials": [ 384 | [ 385 | "Test File", 386 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 387 | ] 388 | ] 389 | }, 390 | "CSE2202": { 391 | "name": "Object Oriented Programming", 392 | "code": "CSE2202", 393 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 394 | "crh": "3", 395 | "description": "None available", 396 | "materials": [ 397 | [ 398 | "Test File", 399 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 400 | ] 401 | ] 402 | }, 403 | "CSE2206": { 404 | "name": "Discrete Mathematics for CSE", 405 | "code": "CSE2206", 406 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 407 | "crh": "3", 408 | "description": "None available", 409 | "materials": [ 410 | [ 411 | "Test File", 412 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 413 | ] 414 | ] 415 | }, 416 | "ECE3204": { 417 | "name": "Digital Logic Design", 418 | "code": "ECE3204", 419 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 420 | "crh": "3", 421 | "description": "None available", 422 | "materials": [ 423 | [ 424 | "Test File", 425 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 426 | ] 427 | ] 428 | }, 429 | "CSE3207": { 430 | "name": "Database Systems", 431 | "code": "CSE3207", 432 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 433 | "crh": "3", 434 | "description": "None available", 435 | "materials": [ 436 | [ 437 | "Test File", 438 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 439 | ] 440 | ] 441 | }, 442 | "ECE2202": { 443 | "name": "Electronic circuit II", 444 | "code": "ECE2202", 445 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 446 | "crh": "3", 447 | "description": "None available", 448 | "materials": [ 449 | [ 450 | "Test File", 451 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 452 | ] 453 | ] 454 | }, 455 | "CSE2320": { 456 | "name": "System Programming", 457 | "code": "CSE2320", 458 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 459 | "crh": "3", 460 | "description": "None available", 461 | "materials": [ 462 | [ 463 | "Test File", 464 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 465 | ] 466 | ] 467 | }, 468 | "CSE3310": { 469 | "name": "Computer Graphics", 470 | "code": "CSE3310", 471 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 472 | "crh": "3", 473 | "description": "None available", 474 | "materials": [ 475 | [ 476 | "Test File", 477 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 478 | ] 479 | ] 480 | }, 481 | "CSE3211": { 482 | "name": "Algorithms", 483 | "code": "CSE3211", 484 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 485 | "crh": "3", 486 | "description": "None available", 487 | "materials": [ 488 | [ 489 | "Test File", 490 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 491 | ] 492 | ] 493 | }, 494 | "ECE3103": { 495 | "name": "Probability and Random Process", 496 | "code": "ECE3103", 497 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 498 | "crh": "3", 499 | "description": "None available", 500 | "materials": [ 501 | [ 502 | "Test File", 503 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 504 | ] 505 | ] 506 | }, 507 | "CSE3205": { 508 | "name": "Fund. of software Engineering", 509 | "code": "CSE3205", 510 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 511 | "crh": "3", 512 | "description": "None available", 513 | "materials": [ 514 | [ 515 | "Test File", 516 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 517 | ] 518 | ] 519 | }, 520 | "CSE3203": { 521 | "name": "Computer Architecture & Organization", 522 | "code": "CSE3203", 523 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 524 | "crh": "3", 525 | "description": "None available", 526 | "materials": [ 527 | [ 528 | "Test File", 529 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 530 | ] 531 | ] 532 | }, 533 | "CSE3204": { 534 | "name": "Operating System", 535 | "code": "CSE3204", 536 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 537 | "crh": "3", 538 | "description": "None available", 539 | "materials": [ 540 | [ 541 | "Test File", 542 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 543 | ] 544 | ] 545 | }, 546 | "CSE3221": { 547 | "name": "Data Communication & Computer Networks", 548 | "code": "CSE3221", 549 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 550 | "crh": "3", 551 | "description": "None available", 552 | "materials": [ 553 | [ 554 | "Test File", 555 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 556 | ] 557 | ] 558 | }, 559 | "CSE3206": { 560 | "name": "Introduction to Artificial", 561 | "code": "CSE3206", 562 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 563 | "crh": "3", 564 | "description": "None available", 565 | "materials": [ 566 | [ 567 | "Test File", 568 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 569 | ] 570 | ] 571 | }, 572 | "CSE3308": { 573 | "name": "SOftware Requirement Engineering", 574 | "code": "CSE3308", 575 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 576 | "crh": "3", 577 | "description": "None available", 578 | "materials": [ 579 | [ 580 | "Test File", 581 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 582 | ] 583 | ] 584 | }, 585 | "CSE3306": { 586 | "name": "Web Programming", 587 | "code": "CSE3306", 588 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 589 | "crh": "3", 590 | "description": "None available", 591 | "materials": [ 592 | [ 593 | "Test File", 594 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 595 | ] 596 | ] 597 | }, 598 | "CSE3312": { 599 | "name": "Advanced Programming", 600 | "code": "CSE3312", 601 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 602 | "crh": "3", 603 | "description": "None available", 604 | "materials": [ 605 | [ 606 | "Test File", 607 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 608 | ] 609 | ] 610 | }, 611 | "UNKNOWN": { 612 | "name": "Introduction to Law", 613 | "code": "Unknown", 614 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 615 | "crh": "3", 616 | "description": "None available", 617 | "materials": [ 618 | [ 619 | "Test File", 620 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 621 | ] 622 | ] 623 | }, 624 | "CSE4221": { 625 | "name": "Engineering Research and Development Methodology", 626 | "code": "CSE4221", 627 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 628 | "crh": "3", 629 | "description": "None available", 630 | "materials": [ 631 | [ 632 | "Test File", 633 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 634 | ] 635 | ] 636 | }, 637 | "CSE4303": { 638 | "name": "Multimedia Tech.", 639 | "code": "CSE4303", 640 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 641 | "crh": "3", 642 | "description": "None available", 643 | "materials": [ 644 | [ 645 | "Test File", 646 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 647 | ] 648 | ] 649 | }, 650 | "CSE4309": { 651 | "name": "Software Design and Architecture", 652 | "code": "CSE4309", 653 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 654 | "crh": "3", 655 | "description": "None available", 656 | "materials": [ 657 | [ 658 | "Test File", 659 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 660 | ] 661 | ] 662 | }, 663 | "CSE4311": { 664 | "name": "Mobile Computing and Applications", 665 | "code": "CSE4311", 666 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 667 | "crh": "3", 668 | "description": "None available", 669 | "materials": [ 670 | [ 671 | "Test File", 672 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 673 | ] 674 | ] 675 | }, 676 | "ECE2204": { 677 | "name": "Signals and Systems", 678 | "code": "ECE2204", 679 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 680 | "crh": "3", 681 | "description": "None available", 682 | "materials": [ 683 | [ 684 | "Test File", 685 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 686 | ] 687 | ] 688 | }, 689 | "CSE5317": { 690 | "name": "Introduction to Data mining", 691 | "code": "CSE5317", 692 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 693 | "crh": "3", 694 | "description": "None available", 695 | "materials": [ 696 | [ 697 | "Test File", 698 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 699 | ] 700 | ] 701 | }, 702 | "CSE5321": { 703 | "name": "Introduction to NLP", 704 | "code": "CSE5321", 705 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 706 | "crh": "3", 707 | "description": "None available", 708 | "materials": [ 709 | [ 710 | "Test File", 711 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 712 | ] 713 | ] 714 | }, 715 | "UNKOWN": { 716 | "name": "Computer System and security", 717 | "code": "Unkown", 718 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 719 | "crh": "3", 720 | "description": "None available", 721 | "materials": [ 722 | [ 723 | "Test File", 724 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 725 | ] 726 | ] 727 | }, 728 | "CSE4202": { 729 | "name": "Programming languages", 730 | "code": "CSE4202", 731 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 732 | "crh": "3", 733 | "description": "None available", 734 | "materials": [ 735 | [ 736 | "Test File", 737 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 738 | ] 739 | ] 740 | }, 741 | "CSE4302": { 742 | "name": "Project Management", 743 | "code": "CSE4302", 744 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 745 | "crh": "3", 746 | "description": "None available", 747 | "materials": [ 748 | [ 749 | "Test File", 750 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 751 | ] 752 | ] 753 | }, 754 | "CSE4310": { 755 | "name": "Compiler Design", 756 | "code": "CSE4310", 757 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 758 | "crh": "3", 759 | "description": "None available", 760 | "materials": [ 761 | [ 762 | "Test File", 763 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 764 | ] 765 | ] 766 | }, 767 | "ECE3205": { 768 | "name": "Digital Signal Processing", 769 | "code": "ECE3205", 770 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 771 | "crh": "3", 772 | "description": "None available", 773 | "materials": [ 774 | [ 775 | "Test File", 776 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 777 | ] 778 | ] 779 | }, 780 | "ECE5307": { 781 | "name": "VLSI Design", 782 | "code": "ECE5307", 783 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 784 | "crh": "3", 785 | "description": "None available", 786 | "materials": [ 787 | [ 788 | "Test File", 789 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 790 | ] 791 | ] 792 | }, 793 | "PCE3201": { 794 | "name": "Electrical Network Analysis and synthesis", 795 | "code": "PCE3201", 796 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 797 | "crh": "3", 798 | "description": "None available", 799 | "materials": [ 800 | [ 801 | "Test File", 802 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 803 | ] 804 | ] 805 | }, 806 | "CSE4312": { 807 | "name": "Introduction to Computer Vision", 808 | "code": "CSE4312", 809 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 810 | "crh": "3", 811 | "description": "None available", 812 | "materials": [ 813 | [ 814 | "Test File", 815 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 816 | ] 817 | ] 818 | }, 819 | "CSE5201": { 820 | "name": "Semester Project", 821 | "code": "CSE5201", 822 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 823 | "crh": "3", 824 | "description": "None available", 825 | "materials": [ 826 | [ 827 | "Test File", 828 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 829 | ] 830 | ] 831 | }, 832 | "CSE5205": { 833 | "name": "Seminar", 834 | "code": "CSE5205", 835 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 836 | "crh": "3", 837 | "description": "None available", 838 | "materials": [ 839 | [ 840 | "Test File", 841 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 842 | ] 843 | ] 844 | }, 845 | "CSE5307": { 846 | "name": "Distributed Systems", 847 | "code": "CSE5307", 848 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 849 | "crh": "3", 850 | "description": "None available", 851 | "materials": [ 852 | [ 853 | "Test File", 854 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 855 | ] 856 | ] 857 | }, 858 | "CSE5309": { 859 | "name": "Wireless mobile Networks", 860 | "code": "CSE5309", 861 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 862 | "crh": "3", 863 | "description": "None available", 864 | "materials": [ 865 | [ 866 | "Test File", 867 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 868 | ] 869 | ] 870 | }, 871 | "CSE5311": { 872 | "name": "Image Processing", 873 | "code": "CSE5311", 874 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 875 | "crh": "3", 876 | "description": "None available", 877 | "materials": [ 878 | [ 879 | "Test File", 880 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 881 | ] 882 | ] 883 | }, 884 | "CSE5313": { 885 | "name": "Human Computer Interaction", 886 | "code": "CSE5313", 887 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 888 | "crh": "3", 889 | "description": "None available", 890 | "materials": [ 891 | [ 892 | "Test File", 893 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 894 | ] 895 | ] 896 | }, 897 | "CSE5315": { 898 | "name": "Introduction to Audio & Video Production", 899 | "code": "CSE5315", 900 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 901 | "crh": "3", 902 | "description": "None available", 903 | "materials": [ 904 | [ 905 | "Test File", 906 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 907 | ] 908 | ] 909 | }, 910 | "CSE5319": { 911 | "name": "Advanced Network", 912 | "code": "CSE5319", 913 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 914 | "crh": "3", 915 | "description": "None available", 916 | "materials": [ 917 | [ 918 | "Test File", 919 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 920 | ] 921 | ] 922 | }, 923 | "PCE3204": { 924 | "name": "Introduction to Control Systems", 925 | "code": "PCE3204", 926 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 927 | "crh": "3", 928 | "description": "None available", 929 | "materials": [ 930 | [ 931 | "Test File", 932 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 933 | ] 934 | ] 935 | }, 936 | "CSE5202": { 937 | "name": "B.Sc. Project", 938 | "code": "CSE5202", 939 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 940 | "crh": "3", 941 | "description": "None available", 942 | "materials": [ 943 | [ 944 | "Test File", 945 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 946 | ] 947 | ] 948 | }, 949 | "SOSC412": { 950 | "name": "Entrepreneurship for Engineers", 951 | "code": "SOSC412", 952 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 953 | "crh": "3", 954 | "description": "None available", 955 | "materials": [ 956 | [ 957 | "Test File", 958 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 959 | ] 960 | ] 961 | }, 962 | "CSE5304": { 963 | "name": "Computer Games & Animation", 964 | "code": "CSE5304", 965 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 966 | "crh": "3", 967 | "description": "None available", 968 | "materials": [ 969 | [ 970 | "Test File", 971 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 972 | ] 973 | ] 974 | }, 975 | "CSE5306": { 976 | "name": "Special Topics in Computer Science & Engineering", 977 | "code": "CSE5306", 978 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 979 | "crh": "3", 980 | "description": "None available", 981 | "materials": [ 982 | [ 983 | "Test File", 984 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 985 | ] 986 | ] 987 | }, 988 | "CSE5308": { 989 | "name": "Real time and Embedded Systems", 990 | "code": "CSE5308", 991 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 992 | "crh": "3", 993 | "description": "None available", 994 | "materials": [ 995 | [ 996 | "Test File", 997 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 998 | ] 999 | ] 1000 | }, 1001 | "CSE5310": { 1002 | "name": "Software Quality & Testing", 1003 | "code": "CSE5310", 1004 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 1005 | "crh": "3", 1006 | "description": "None available", 1007 | "materials": [ 1008 | [ 1009 | "Test File", 1010 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 1011 | ] 1012 | ] 1013 | }, 1014 | "CSE5312": { 1015 | "name": "Computer Ethics and Social Issues", 1016 | "code": "CSE5312", 1017 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 1018 | "crh": "3", 1019 | "description": "None available", 1020 | "materials": [ 1021 | [ 1022 | "Test File", 1023 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 1024 | ] 1025 | ] 1026 | }, 1027 | "PCE5308": { 1028 | "name": "Introduction to Robotics and Industrial Automation", 1029 | "code": "PCE5308", 1030 | "file_id": "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME", 1031 | "crh": "3", 1032 | "description": "None available", 1033 | "materials": [ 1034 | [ 1035 | "Test File", 1036 | "BQACAgQAAxkBAAEN4Q5h_Se8R-cPMRGuyubQ72-JiDOpjgACoAkAAld7KFPIdWJ0Hn4oNiME" 1037 | ] 1038 | ] 1039 | } 1040 | } --------------------------------------------------------------------------------