├── 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 |
4 |
5 |
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 | }
--------------------------------------------------------------------------------