initial development checkpoint 4

This commit is contained in:
2024-06-01 19:45:47 +03:00
parent 54377708b0
commit fbdc014bf4
11 changed files with 393 additions and 34 deletions

View File

@@ -54,11 +54,17 @@ class Question:
rop = ResponseOptionPool(cur)
return "<br>".join([i.render_short() for i in rop.select_by_question_id(self.id)])
def get_correct_response_percentage(self, cur):
rop = ResponseOptionPool(cur)
response_options = rop.select_by_question_id(self.id)
return sum([int(i.get_correctness()) for i in response_options]) / len(response_options) * 100
def render_short(self, cur):
time_label = self.get_time_label()
response_options = self.get_response_option_short_list(cur)
correct_percentage = round(self.get_correct_response_percentage(cur))
return f'<div class="question-short"><a class="question-link" href="/index.py?mode=view-question&id={self.id}"><span class="sub-label">#{self.id}</span><span class="main-label">{self.title}</span></a><span class="sub-title">{time_label}</span><div class="response-option-short-list">{response_options}</div><div class="controls"><a class="sub-button" href="/index.py?mode=edit-question&id={self.id}">Редагувати</a><a class="scary-button" href="/index.py?mode=delete-question&id={self.id}">Видалити</a></div></div>'
return f'<div class="question-short"><a class="question-link" href="/index.py?mode=view-question&id={self.id}"><span class="sub-label">#{self.id}</span><span class="main-label">{self.title}</span></a><span class="sub-title">{time_label}<br>{correct_percentage}% відповідей правильні</span><div class="response-option-short-list">{response_options}</div><div class="controls"><a class="magic-button" href="?mode=generate-response-options&id={self.id}">Згенерувати відповіді</a><a class="sub-button" href="/index.py?mode=edit-question&id={self.id}">Редагувати</a><a class="scary-button" href="/index.py?mode=delete-question&id={self.id}">Видалити</a></div></div>'
class QuestionPool:
def __init__(self, db):

View File

@@ -22,7 +22,7 @@ class ResponseOption:
return self.questionID
def get_correctness(self):
return correctness
return self.correctness
def render_short(self):
if self.correctness:

View File

@@ -17,7 +17,7 @@ class Test:
return self.name
def render_short(self):
return f'<div class="test-short"><a class="test-link" href="/index.py?mode=view-test&id={self.id}"><span class="sub-label">#{self.id}</span><span class="main-label">{self.name}</span></a></div>'
return f'<div class="test-short"><a class="test-link" href="/index.py?mode=view-test&id={self.id}"><span class="sub-label">#{self.id}</span><span class="main-label">{self.name}</span></a><div class="controls"><a class="sub-button" href="?mode=edit-test&id={self.id}">Редагувати</a><a class="scary-button" href="?mode=delete-test&id={self.id}">Видалити</a></div></div>'
class TestPool:
def __init__(self, db):

View File

@@ -13,3 +13,34 @@ class QuestionList:
rendered_questions = [i.render_short(self.cursor) for i in qp.iter()]
return "\n".join(rendered_questions)
def count(self):
qp = QuestionPool(self.cursor)
return len(qp.object_pool.pool)
def get_avg_time(self):
qp = QuestionPool(self.cursor)
avg_time = sum([i.get_max_time() for i in qp.iter()]) / len(qp.object_pool.pool)
return self.get_time_label(avg_time)
def get_time_label(self, max_time):
total_time = max_time
hours = total_time // 3600
total_time -= hours * 3600
minutes = total_time // 60
total_time -= minutes * 60
seconds = total_time
total_label = []
if hours:
total_label.append(f"{round(hours)} год.")
if minutes:
total_label.append(f"{round(minutes)} хв.")
if seconds:
total_label.append(f"{round(seconds)} c.")
return " ".join(total_label)

View File

@@ -13,3 +13,10 @@ class ResponseOptionList:
rendered_response_options = [i.render_full() for i in rop.iter()]
return "\n".join(rendered_response_options)
def count(self, correct = False):
rop = ResponseOptionPool(self.cursor)
if correct:
return len([i for i in rop.object_pool.pool if i.get_correctness()])
else:
return len(rop.object_pool.pool)

View File

@@ -6,7 +6,14 @@ class TestList:
def __init__(self, cursor):
self.cursor = cursor
def render(self):
def render(self, *args):
tp = TestPool(self.cursor)
rendered_chunks = [i.render_short() for i in tp.object_pool.pool]
if len(args) > 0:
rendered_chunks = [i.render_short() for i in tp.object_pool.pool if args[0] in i.get_name()]
else:
rendered_chunks = [i.render_short() for i in tp.object_pool.pool]
return "\n".join(rendered_chunks)
def count(self):
tp = TestPool(self.cursor)
return len(tp.object_pool.pool)

View File

@@ -20,6 +20,8 @@ class View:
self.supported_modes = {
"test-list": self.render_test_list,
"create-test": self.render_create_test,
"edit-test": self.render_edit_test,
"delete-test": self.render_delete_test,
"view-test": self.render_view_test,
"create-question": self.render_create_question,
"edit-question": self.render_edit_question,
@@ -28,6 +30,8 @@ class View:
"create-response-option": self.render_create_response_option,
"edit-response-option": self.render_edit_response_option,
"delete-response-option": self.render_delete_response_option,
"generate-response-options": self.render_generate_response_options,
"view-stats": self.render_view_stats
}
def get_db_connection(self):
@@ -79,10 +83,19 @@ class View:
cur.execute("SELECT id FROM test;")
test_amount = len(list(cur))
header = f'<h2>Всього тестів: {test_amount}</h2>'
if 'search' in self.args:
search = self.args['search']
else:
search = ""
subheader = f'<input placeholder="Шукати тести"><br><a class="generic-button" href="?mode=create-test">Створити новий тест</a>'
subheader = f'<form action="/index.py"><input name="search" placeholder="Шукати тести" value="{search}"></form><br><a class="generic-button" href="?mode=create-test">Створити новий тест</a><a class="sub-button" href="?mode=view-stats">Переглянути статистику</a>'
content = TestList(cur).render()
tl = TestList(cur)
if 'search' in self.args:
content = tl.render(self.args['search'])
else:
content = tl.render()
return header, subheader, content
@@ -93,11 +106,50 @@ class View:
content = f'''<form action="/create-test.py">
<label for="name">Назва тесту:</label>
<input type="text" name="name" placeholder="Введіть назву..." required><br>
<input type="submit" value="Створити">
<input type="submit" class="submit-button" value="Створити">
</form>'''
return header, subheader, content
def render_edit_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"<h2>Редагувати тест</h2>"
subheader = "<i>Вкажіть нові властивості тесту нижче</i>"
content = f'''<form action="/edit-test.py">
<input type="text" name="id" value="{self.args['id']}" style="display:none;">
<label for="name">Назва тесту:</label>
<input type="text" name="name" placeholder="Введіть назву..." value="{test_name}" required><br>
<input type="submit" class="submit-button" value="Зберегти">
</form>'''
return header, subheader, content
def render_delete_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"<h2>Точно видалити цей тест?</h2>"
subheader = f"<i>{test_name}</i>"
content = f'''<div class="return-button-centerer"><a class="delete-button" href="/delete-test.py?id={self.args["id"]}">Так, видалити</a><br><a class="cancel-button" href="/">Ні, залишити</a></div>'''
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]
@@ -110,7 +162,7 @@ class View:
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>'
subheader = f'<a class="generic-button" href="?mode=create-question&test_id={self.args["id"]}">Додати запитання</a><a class="sub-button" href="?mode=edit-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>'
@@ -127,7 +179,7 @@ class View:
<input type="text" name="title" placeholder="Введіть запитання..." required><br>
<label for="mtime">Максимальний час на відповідь (в сек):</label>
<input type="number" name="mtime" placeholder="Наприклад, 120"><br>
<input type="submit" value="Додати">
<input type="submit" class="submit-button" value="Додати">
</form>'''
return header, subheader, content
@@ -151,7 +203,7 @@ class View:
<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="Зберегти зміни">
<input type="submit" class="submit-button" value="Зберегти">
</form>'''
return header, subheader, content
@@ -172,7 +224,7 @@ class View:
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>'''
content = f'''<div class="return-button-centerer"><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></div>'''
return header, subheader, content
@@ -211,7 +263,7 @@ class View:
<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="Додати">
<input type="submit" class="submit-button" value="Додати">
</form>'''
return header, subheader, content
@@ -227,7 +279,7 @@ class View:
<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="Оновити">
<input type="submit" class="submit-button" value="Зберегти">
</form>'''
return header, subheader, content
@@ -242,6 +294,38 @@ class View:
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>'''
content = f'''<div class="return-button-centerer"><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></div>'''
return header, subheader, content
def render_generate_response_options(self, cur):
header = f"<h2>Генерація варіантів відповідей</h2>"
subheader = f"<i>Вкажіть параметри генерації нижче</i>"
content = f'''<form action="/generate-response-options.py">
<input type="text" name="id" value="{self.args["id"]}" style="display:none;">
<label for="label">Кількість варіантів:</label>
<input type="number" name="amount" placeholder="Наприклад, 4" required><br>
<input type="submit" class="magic-button" value="Згенерувати">
</form>'''
return header, subheader, content
def render_view_stats(self, cur):
header = f"<h2>Статистика системи</h2>"
subheader = f'<a class="sub-button" href="/">Повернутися на головну сторінку</a>'
content = f''''''
test_count = TestList(cur).count()
content += f'<div class="piece-of-stats"><span class="header">Тести</span>Всього тестів: {test_count}</div>'
question_count = QuestionList(cur).count()
question_avg_time = QuestionList(cur).get_avg_time()
content += f'<div class="piece-of-stats"><span class="header">Запитання</span>Всього запитань: {question_count} (в середньому по {round(question_count/test_count, 3)} зап./тест)<br>В середньому на запитання дається {question_avg_time}</div>'
rol = ResponseOptionList(cur)
response_option_count = rol.count()
response_option_count_correct = rol.count(correct = True)
content += f'<div class="piece-of-stats"><span class="header">Варіанти відповідей</span>Всього варіантів відповідей: {response_option_count}<br>З-поміж них правильних: {response_option_count_correct} ({round(response_option_count_correct/response_option_count*100, 2)}%)</div>'
return header, subheader, content