248 lines
12 KiB
Python
248 lines
12 KiB
Python
import mariadb as mdb
|
||
import json
|
||
import os
|
||
|
||
from test_list import TestList
|
||
from question_list import QuestionList
|
||
from response_option_list import ResponseOptionList
|
||
|
||
from httputils import escape_html
|
||
|
||
def readfile(path):
|
||
if os.path.exists(path):
|
||
return open(path).read()
|
||
|
||
class View:
|
||
def __init__(self, query_args, connector_data = {}):
|
||
self.args = query_args
|
||
self.connector_data = connector_data
|
||
self.db_connection = None
|
||
self.supported_modes = {
|
||
"test-list": self.render_test_list,
|
||
"create-test": self.render_create_test,
|
||
"view-test": self.render_view_test,
|
||
"create-question": self.render_create_question,
|
||
"edit-question": self.render_edit_question,
|
||
"delete-question": self.render_delete_question,
|
||
"view-question": self.render_view_question,
|
||
"create-response-option": self.render_create_response_option,
|
||
"edit-response-option": self.render_edit_response_option,
|
||
"delete-response-option": self.render_delete_response_option,
|
||
}
|
||
|
||
def get_db_connection(self):
|
||
if not self.db_connection:
|
||
args = {"host": "127.0.0.1",
|
||
"port": 3306,
|
||
"user": "root",
|
||
"password": "",
|
||
"database": "test_holder"}
|
||
|
||
settings = json.loads(readfile("cgi/db-settings.json"))
|
||
args.update(settings)
|
||
|
||
args.update(self.connector_data)
|
||
|
||
self.db_connection = mdb.connect(**args)
|
||
|
||
return self.db_connection
|
||
|
||
def format_page(self, header, subheader, content):
|
||
base_layout = readfile("html/base_layout.html")
|
||
|
||
base_layout = base_layout.replace("%HEADER%", header)
|
||
base_layout = base_layout.replace("%SUBHEADER%", subheader)
|
||
base_layout = base_layout.replace("%CONTENT%", content)
|
||
|
||
return base_layout
|
||
|
||
def render_page(self):
|
||
dbc = self.get_db_connection()
|
||
cur = dbc.cursor()
|
||
|
||
if 'mode' in self.args:
|
||
mode = self.args['mode']
|
||
else:
|
||
mode = "test-list"
|
||
|
||
if mode not in self.supported_modes:
|
||
header = f"<h2>No such view mode: {mode}</h2>"
|
||
subheader = f'<a href="/index.py">Повернутися на головну сторінку</a>'
|
||
content = ""
|
||
else:
|
||
header, subheader, content = self.supported_modes[mode](cur)
|
||
|
||
dbc.close()
|
||
return self.format_page(header, subheader, content)
|
||
|
||
def render_test_list(self, cur):
|
||
cur.execute("SELECT id FROM test;")
|
||
test_amount = len(list(cur))
|
||
header = f'<h2>Всього тестів: {test_amount}</h2>'
|
||
|
||
subheader = f'<input placeholder="Шукати тести"><br><a class="generic-button" href="?mode=create-test">Створити новий тест</a>'
|
||
|
||
content = TestList(cur).render()
|
||
|
||
return header, subheader, content
|
||
|
||
def render_create_test(self, cur):
|
||
header = f"<h2>Створити новий тест</h2>"
|
||
subheader = "<i>Введіть властивості нового тесту нижче</i>"
|
||
|
||
content = f'''<form action="/create-test.py">
|
||
<label for="name">Назва тесту:</label>
|
||
<input type="text" name="name" placeholder="Введіть назву..." required><br>
|
||
<input type="submit" value="Створити">
|
||
</form>'''
|
||
|
||
return header, subheader, content
|
||
|
||
def render_view_test(self, cur):
|
||
cur.execute(f"SELECT name FROM test WHERE id = {self.args['id']};")
|
||
test_name = next(iter(cur), [None])[0]
|
||
|
||
if not test_name:
|
||
header = f"<h2>Такого тесту не існує: {self.args['id']}</h2>"
|
||
subheader = f'<a href="/index.py">Повернутися на головну сторінку</a>'
|
||
content = ""
|
||
return header, subheader, content
|
||
|
||
header = f'<span class="view-test-id-tag">#{self.args["id"]}</span><span class="view-test-main-tag">{test_name}</span>'
|
||
|
||
subheader = f'<a class="generic-button" href="?mode=create-question&test_id={self.args["id"]}">Додати запитання</a>'
|
||
|
||
content = QuestionList(cur).render(self.args['id'])
|
||
content += '<div class="return-button-centerer"><a class="return-button" href="/index.py">Назад до переліку тестів</a></div>'
|
||
|
||
return header, subheader, content
|
||
|
||
def render_create_question(self, cur):
|
||
header = f"<h2>Додати нове запитання</h2>"
|
||
subheader = "<i>Введіть властивості нового запитання нижче</i>"
|
||
|
||
content = f'''<form action="/create-question.py">
|
||
<input type="text" name="test_id" value="{self.args["test_id"]}" style="display:none;">
|
||
<label for="title">Текст запитання:</label>
|
||
<input type="text" name="title" placeholder="Введіть запитання..." required><br>
|
||
<label for="mtime">Максимальний час на відповідь (в сек):</label>
|
||
<input type="number" name="mtime" placeholder="Наприклад, 120"><br>
|
||
<input type="submit" value="Додати">
|
||
</form>'''
|
||
|
||
return header, subheader, content
|
||
|
||
def render_edit_question(self, cur):
|
||
cur.execute(f"SELECT title, mtime FROM question WHERE id = {self.args['id']};")
|
||
question_title, question_max_time = next(iter(cur), [None, None])
|
||
|
||
if not question_title:
|
||
header = f"<h2>Такого запитання не існує: {self.args['id']}</h2>"
|
||
subheader = f'<a href="/index.py">Повернутися на головну сторінку</a>'
|
||
content = ""
|
||
return header, subheader, content
|
||
|
||
header = f"<h2>Змінити запитання</h2>"
|
||
subheader = "<i>Відредагуйте властивості запитання нижче</i>"
|
||
|
||
content = f'''<form action="/edit-question.py">
|
||
<input type="text" name="question_id" value="{self.args["id"]}" style="display:none;">
|
||
<label for="title">Текст запитання:</label>
|
||
<input type="text" name="title" placeholder="Введіть запитання..." value="{escape_html(question_title)}" required><br>
|
||
<label for="mtime">Максимальний час на відповідь (в сек):</label>
|
||
<input type="number" name="mtime" placeholder="Наприклад, 120" value="{question_max_time}"><br>
|
||
<input type="submit" value="Зберегти зміни">
|
||
</form>'''
|
||
|
||
return header, subheader, content
|
||
|
||
def render_delete_question(self, cur):
|
||
cur.execute(f"SELECT title FROM question WHERE id = {self.args['id']};")
|
||
question_title = next(iter(cur), [None])[0]
|
||
|
||
if not question_title:
|
||
header = f"<h2>Такого запитання не існує: {self.args['id']}</h2>"
|
||
subheader = f'<a href="/index.py">Повернутися на головну сторінку</a>'
|
||
content = ""
|
||
return header, subheader, content
|
||
|
||
header = f"<h2>Точно видалити запитання?</h2>"
|
||
subheader = f"<i>{question_title}</i>"
|
||
|
||
cur.execute(f"SELECT test.id FROM test JOIN question ON test.id = question.tstID WHERE question.id = {self.args['id']};")
|
||
test_id = iter(cur).__next__()[0]
|
||
|
||
content = f'''<a class="delete-button" href="/delete-question.py?id={self.args["id"]}">Так, видалити</a><br><a class="cancel-button" href="/index.py?mode=view-test&id={test_id}">Ні, залишити</a>'''
|
||
|
||
return header, subheader, content
|
||
|
||
def render_view_question(self, cur):
|
||
cur.execute(f"SELECT title FROM question WHERE id = {self.args['id']};")
|
||
question_name = next(iter(cur), [None])[0]
|
||
|
||
if not question_name:
|
||
header = f"<h2>Такого запитання не існує: {self.args['id']}</h2>"
|
||
subheader = f'<a href="/index.py">Повернутися на головну сторінку</a>'
|
||
content = ""
|
||
return header, subheader, content
|
||
|
||
header = f'<span class="view-test-id-tag">#{self.args["id"]}</span><span class="view-test-main-tag">{question_name}</span>'
|
||
|
||
subheader = f'<a class="generic-button" href="?mode=create-response-option&question_id={self.args["id"]}">Додати варіант відповіді</a>' + \
|
||
f'<a class="sub-button" href="?mode=edit-question&id={self.args["id"]}">Редагувати запитання</a>'
|
||
|
||
content = ResponseOptionList(cur).render(self.args['id'])
|
||
|
||
cur.execute(f"""SELECT test.id FROM test
|
||
JOIN question ON test.id = question.tstID
|
||
WHERE question.id = {self.args['id']};""")
|
||
test_id = iter(cur).__next__()[0]
|
||
|
||
content += f'<div class="return-button-centerer"><a class="return-button" href="/index.py?mode=view-test&id={test_id}">Назад до тесту</a></div>'
|
||
|
||
|
||
return header, subheader, content
|
||
|
||
def render_create_response_option(self, cur):
|
||
header = f"<h2>Додати новий варіант відповіді</h2>"
|
||
subheader = "<i>Введіть властивості варіанту відповіді нижче</i>"
|
||
|
||
content = f'''<form action="/create-response-option.py">
|
||
<input type="text" name="question_id" value="{self.args["question_id"]}" style="display:none;">
|
||
<label for="label">Текст відповіді:</label>
|
||
<input type="text" name="label" placeholder="Введіть текст відповіді..." required><br>
|
||
<input type="submit" value="Додати">
|
||
</form>'''
|
||
|
||
return header, subheader, content
|
||
|
||
def render_edit_response_option(self, cur):
|
||
cur.execute(f"SELECT label FROM response_option WHERE id = {self.args['id']};")
|
||
respose_option_label = next(iter(cur), [None])[0]
|
||
|
||
header = f"<h2>Редагувати варіант відповіді</h2>"
|
||
subheader = "<i>Введіть властивості варіанту відповіді нижче</i>"
|
||
|
||
content = f'''<form action="/edit-response-option.py">
|
||
<input type="text" name="id" value="{self.args["id"]}" style="display:none;">
|
||
<label for="label">Текст відповіді:</label>
|
||
<input type="text" name="label" placeholder="Введіть текст відповіді..." value="{respose_option_label}" required><br>
|
||
<input type="submit" value="Оновити">
|
||
</form>'''
|
||
|
||
return header, subheader, content
|
||
|
||
def render_delete_response_option(self, cur):
|
||
cur.execute(f"SELECT label FROM response_option WHERE id = {self.args['id']};")
|
||
response_option_label = next(iter(cur), [None])[0]
|
||
|
||
header = f"<h2>Точно видалити цей варіант відповіді?</h2>"
|
||
subheader = f"<i>{response_option_label}</i>"
|
||
|
||
cur.execute(f"SELECT question.id FROM question JOIN response_option ON question.id = response_option.qstID WHERE response_option.id = {self.args['id']};")
|
||
quest_id = iter(cur).__next__()[0]
|
||
|
||
content = f'''<a class="delete-button" href="/delete-response-option.py?id={self.args["id"]}">Так, видалити</a><br><a class="cancel-button" href="/index.py?mode=view-question&id={quest_id}">Ні, залишити</a>'''
|
||
|
||
return header, subheader, content
|