From 54377708b0260e879af8154bcfe92101bcc19afe Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sat, 1 Jun 2024 13:49:13 +0300 Subject: [PATCH] initial development checkpoint 3 --- server/cgi/db/question.py | 31 ++++++++-------- server/cgi/db/response_option.py | 2 +- server/cgi/question_list.py | 4 +- server/cgi/view.py | 64 +++++++++++++++++++++++++++++++- server/create-question.py | 2 +- server/css/base_style.css | 34 +++++++++++++++-- server/delete-question.py | 41 ++++++++++++++++++++ server/delete-response-option.py | 41 ++++++++++++++++++++ server/edit-response-option.py | 45 ++++++++++++++++++++++ 9 files changed, 240 insertions(+), 24 deletions(-) create mode 100644 server/delete-question.py create mode 100644 server/delete-response-option.py create mode 100644 server/edit-response-option.py diff --git a/server/cgi/db/question.py b/server/cgi/db/question.py index 6edf398..530fc43 100644 --- a/server/cgi/db/question.py +++ b/server/cgi/db/question.py @@ -1,4 +1,5 @@ from db.object_pool import ObjectPool +from db.response_option import ResponseOptionPool class Question: def init(self, sID, title, max_time, test_id): @@ -24,7 +25,10 @@ class Question: def get_test_id(self): return self.test_id - def render_short(self): + def get_time_label(self): + if int(self.max_time) == 0: + return "Час на відповідь не обмежений" + total_time = self.max_time hours = total_time // 3600 @@ -36,6 +40,7 @@ class Question: seconds = total_time total_label = [] + if hours: total_label.append(f"{hours} год.") if minutes: @@ -43,23 +48,17 @@ class Question: if seconds: total_label.append(f"{seconds} c.") - total_time = " ".join(total_label) + return "На відповідь є " + " ".join(total_label) + + def get_response_option_short_list(self, cur): + rop = ResponseOptionPool(cur) + return "
".join([i.render_short() for i in rop.select_by_question_id(self.id)]) - if int(self.max_time) > 0: - return f'
#{self.id}{self.title}На відповідь є {total_time}
' - else: - return f'
#{self.id}{self.title}Час на відповідь не обмежений
' + def render_short(self, cur): + time_label = self.get_time_label() + response_options = self.get_response_option_short_list(cur) -''' -class QuestionPool: - def __init__(self): - self.pool = [] - - def load_from_db(self, cur): - db.execute("SELECT * FROM response_option;") - self.pool = [ResponseOption().init_from_data(i) for i in cur] - return self -''' + return f'
#{self.id}{self.title}{time_label}
{response_options}
' class QuestionPool: def __init__(self, db): diff --git a/server/cgi/db/response_option.py b/server/cgi/db/response_option.py index 45133dc..8b822f5 100644 --- a/server/cgi/db/response_option.py +++ b/server/cgi/db/response_option.py @@ -28,7 +28,7 @@ class ResponseOption: if self.correctness: c_mark = "+ " else: - c_mark = " " + c_mark = "- " return f'{c_mark} {self.label}' diff --git a/server/cgi/question_list.py b/server/cgi/question_list.py index 3c32fef..90774eb 100644 --- a/server/cgi/question_list.py +++ b/server/cgi/question_list.py @@ -8,8 +8,8 @@ class QuestionList: qp = QuestionPool(self.cursor) if test_id: - rendered_questions = [i.render_short() for i in qp.select_by_test_id(test_id)] + rendered_questions = [i.render_short(self.cursor) for i in qp.select_by_test_id(test_id)] else: - rendered_questions = [i.render_short() for i in qp.iter()] + rendered_questions = [i.render_short(self.cursor) for i in qp.iter()] return "\n".join(rendered_questions) diff --git a/server/cgi/view.py b/server/cgi/view.py index 1520ccb..c4f170b 100644 --- a/server/cgi/view.py +++ b/server/cgi/view.py @@ -23,8 +23,11 @@ class View: "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): @@ -110,6 +113,7 @@ class View: subheader = f'Додати запитання' content = QuestionList(cur).render(self.args['id']) + content += '
Назад до переліку тестів
' return header, subheader, content @@ -146,11 +150,31 @@ class View:
-
+
''' 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"

Такого запитання не існує: {self.args['id']}

" + subheader = f'Повернутися на головну сторінку' + content = "" + return header, subheader, content + + header = f"

Точно видалити запитання?

" + subheader = f"{question_title}" + + 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'''Так, видалити
Ні, залишити''' + + return header, subheader, content def render_view_question(self, cur): cur.execute(f"SELECT title FROM question WHERE id = {self.args['id']};") @@ -169,6 +193,14 @@ class View: 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'
Назад до тесту
' + + return header, subheader, content def render_create_response_option(self, cur): @@ -183,3 +215,33 @@ class View: ''' 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"

Редагувати варіант відповіді

" + subheader = "Введіть властивості варіанту відповіді нижче" + + content = f'''
+ + +
+ +
''' + + 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"

Точно видалити цей варіант відповіді?

" + subheader = f"{response_option_label}" + + 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'''Так, видалити
Ні, залишити''' + + return header, subheader, content diff --git a/server/create-question.py b/server/create-question.py index 0daf5aa..71d6708 100644 --- a/server/create-question.py +++ b/server/create-question.py @@ -30,7 +30,7 @@ if not 'title' in args: print("Content-Type: text/plain; charset=UTF-8\r\n\r\nВи не зазначили текст запитання\r\n") sys.exit(0) -if not 'mtime' in args: +if (not 'mtime' in args) or (not args['mtime']): args['mtime'] = 0 cur = db_connection.cursor() diff --git a/server/css/base_style.css b/server/css/base_style.css index 81d44c3..b9a06f7 100644 --- a/server/css/base_style.css +++ b/server/css/base_style.css @@ -57,7 +57,8 @@ header .top-half .view-test-main-tag { header .lower-half a.generic-button, header .lower-half a.sub-button, main * a.sub-button, -main * a.scary-button +main * a.scary-button, +main a.return-button { text-decoration: none; border-radius: 15px; @@ -81,7 +82,8 @@ header .lower-half a.generic-button:hover { } header .lower-half a.sub-button, -main * a.sub-button +main * a.sub-button, +main a.return-button { border: 1px solid #000; } @@ -110,7 +112,7 @@ main .response-option { padding: 20px; background: var(--blue-gradient-glassy); - margin-top: 16px; + margin-bottom: 16px; border-radius: 14px; vertical-align: middle; } @@ -149,6 +151,21 @@ main * .sub-title { margin-top: 12px; } +main * .response-option-short-list +{ + margin-top: 12px; +} + +main * .response-option-short +{ + display: inline-block; + margin-top: 7px; + background: #F1F1F1; + border-radius: 6px; + padding: 4px; + font-weight: 500; +} + main .response-option a.response-option-mark { font-size: 16pt; text-decoration: none; @@ -160,3 +177,14 @@ main .response-option a.response-option-mark { border: solid 1px; font-family: monospace; } + +main .return-button-centerer +{ + display: grid; +} + +main a.return-button +{ + margin: auto; + margin-bottom: 15px; +} diff --git a/server/delete-question.py b/server/delete-question.py new file mode 100644 index 0000000..8f47586 --- /dev/null +++ b/server/delete-question.py @@ -0,0 +1,41 @@ +import mariadb as mdb +import traceback +import json +import sys +import os + +from httputils import parse_query, escape_sql_string + +def readfile(path): + if os.path.exists(path): + return open(path).read() + +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) + +db_connection = mdb.connect(**args) + +args = parse_query(os.environ['QUERY_STRING']) + +if not 'id' in args: + print("Content-Type: text/plain; charset=UTF-8\r\n\r\nВи не зазначили ідентифікатор запитання\r\n") + sys.exit(0) + +cur = db_connection.cursor() + +try: + cur.execute(f"SELECT test.id FROM test JOIN question ON test.id = question.tstID WHERE question.id = {args['id']};") + test_id = iter(cur).__next__()[0] + + cur.execute(f"DELETE FROM question WHERE id = {args['id']};") + db_connection.commit() + + print(f"Location: /index.py?mode=view-test&id={test_id}\r\n\r\n") +except Exception as e: + print(f"Content-Type: text/plain; charset=UTF-8\r\n\r\nНе вдалося видалити запитання ({e})\r\n{traceback.format_exc()}\r\n") diff --git a/server/delete-response-option.py b/server/delete-response-option.py new file mode 100644 index 0000000..1cf7e19 --- /dev/null +++ b/server/delete-response-option.py @@ -0,0 +1,41 @@ +import mariadb as mdb +import traceback +import json +import sys +import os + +from httputils import parse_query, escape_sql_string + +def readfile(path): + if os.path.exists(path): + return open(path).read() + +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) + +db_connection = mdb.connect(**args) + +args = parse_query(os.environ['QUERY_STRING']) + +if not 'id' in args: + print("Content-Type: text/plain; charset=UTF-8\r\n\r\nВи не зазначили ідентифікатор варіанту відповіді\r\n") + sys.exit(0) + +cur = db_connection.cursor() + +try: + cur.execute(f"SELECT question.id FROM question JOIN response_option ON question.id = response_option.qstID WHERE response_option.id = {args['id']};") + quest_id = iter(cur).__next__()[0] + + cur.execute(f"DELETE FROM response_option WHERE id = {args['id']};") + db_connection.commit() + + print(f"Location: /index.py?mode=view-question&id={quest_id}\r\n\r\n") +except Exception as e: + print(f"Content-Type: text/plain; charset=UTF-8\r\n\r\nНе вдалося видалити варіант відповіді ({e})\r\n{traceback.format_exc()}\r\n") diff --git a/server/edit-response-option.py b/server/edit-response-option.py new file mode 100644 index 0000000..8229171 --- /dev/null +++ b/server/edit-response-option.py @@ -0,0 +1,45 @@ +import mariadb as mdb +import traceback +import json +import sys +import os + +from httputils import parse_query, escape_sql_string + +def readfile(path): + if os.path.exists(path): + return open(path).read() + +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) + +db_connection = mdb.connect(**args) + +args = parse_query(os.environ['QUERY_STRING']) + +if not 'id' in args: + print("Content-Type: text/plain; charset=UTF-8\r\n\r\nВи не зазначили ідентифікатор варіанту відповіді\r\n") + sys.exit(0) + +if not 'label' in args: + print("Content-Type: text/plain; charset=UTF-8\r\n\r\nВи не зазначили текст варіанту відповіді\r\n") + sys.exit(0) + +cur = db_connection.cursor() + +try: + cur.execute(f"UPDATE response_option SET label = '{escape_sql_string(args['label'])}' WHERE id = {args['id']};") + db_connection.commit() + + cur.execute(f"SELECT question.id FROM question JOIN response_option ON question.id = response_option.qstID WHERE response_option.id = {args['id']};") + + quest_id = iter(cur).__next__()[0] + print(f"Location: /index.py?mode=view-question&id={quest_id}\r\n\r\n") +except Exception as e: + print(f"Content-Type: text/plain; charset=UTF-8\r\n\r\nНе вдалося створити нове запитання ({e})\r\n{traceback.format_exc()}\r\n")