initial development checkpoint 2
This commit is contained in:
parent
26e912c03a
commit
b4c1a23ce2
|
@ -1,4 +1,4 @@
|
|||
from object_pool import ObjectPool
|
||||
from db.object_pool import ObjectPool
|
||||
|
||||
class Question:
|
||||
def init(self, sID, title, max_time, test_id):
|
||||
|
@ -24,6 +24,32 @@ class Question:
|
|||
def get_test_id(self):
|
||||
return self.test_id
|
||||
|
||||
def render_short(self):
|
||||
total_time = self.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"{hours} год.")
|
||||
if minutes:
|
||||
total_label.append(f"{minutes} хв.")
|
||||
if seconds:
|
||||
total_label.append(f"{seconds} c.")
|
||||
|
||||
total_time = " ".join(total_label)
|
||||
|
||||
if int(self.max_time) > 0:
|
||||
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">На відповідь є {total_time}</span></div>'
|
||||
else:
|
||||
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">Час на відповідь не обмежений</span></div>'
|
||||
|
||||
'''
|
||||
class QuestionPool:
|
||||
def __init__(self):
|
||||
|
@ -36,8 +62,14 @@ class QuestionPool:
|
|||
'''
|
||||
|
||||
class QuestionPool:
|
||||
def __init__(self):
|
||||
def __init__(self, db):
|
||||
self.object_pool = ObjectPool("question", Question)
|
||||
|
||||
if db:
|
||||
self.object_pool.load_from_db(db)
|
||||
|
||||
def iter(self):
|
||||
return iter(self.object_pool.pool)
|
||||
|
||||
def select_by_test_id(self, test_id):
|
||||
return [i for i in self.object_pool.pool if i.get_test_id() == int(test_id)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from object_pool import ObjectPool
|
||||
from db.object_pool import ObjectPool
|
||||
|
||||
class ResponseOption:
|
||||
def init(self, sID, label, questionID, correctness):
|
||||
|
@ -24,20 +24,31 @@ class ResponseOption:
|
|||
def get_correctness(self):
|
||||
return correctness
|
||||
|
||||
class ResponceOptionPool:
|
||||
def __init__(self):
|
||||
def render_short(self):
|
||||
if self.correctness:
|
||||
c_mark = "+ "
|
||||
else:
|
||||
c_mark = " "
|
||||
|
||||
return f'<span class="response-option-short">{c_mark} {self.label}</span>'
|
||||
|
||||
def render_full(self):
|
||||
if self.correctness:
|
||||
c_mark = "+"
|
||||
else:
|
||||
c_mark = "-"
|
||||
|
||||
return f'<div class="response-option"><a class="response-option-mark" href="/flip-correctness.py?res_opt_id={self.id}">{c_mark}</a><span class="response-option-label">{self.label}</span><br><div class="controls"><a class="sub-button" href="/index.py?mode=edit-response-option&id={self.id}">Редагувати</a><a class="scary-button" href="/index.py?mode=delete-response-option&id={self.id}">Видалити</a></div></div>'
|
||||
|
||||
class ResponseOptionPool:
|
||||
def __init__(self, db):
|
||||
self.object_pool = ObjectPool("response_option", ResponseOption)
|
||||
|
||||
if db:
|
||||
self.object_pool.load_from_db(db)
|
||||
|
||||
'''
|
||||
class ResponceOptionPool:
|
||||
def __init__(self):
|
||||
self.pool = []
|
||||
def iter(self):
|
||||
return iter(self.object_pool.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
|
||||
'''
|
||||
def select_by_question_id(self, question_id):
|
||||
return [i for i in self.object_pool.pool if i.get_question_id() == int(question_id)]
|
||||
|
|
|
@ -17,7 +17,7 @@ class Test:
|
|||
return self.name
|
||||
|
||||
def render_short(self):
|
||||
return f'<div class="test-short"><a class="header-link">#{self.sID} {self.name}</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 TestPool:
|
||||
def __init__(self, db):
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
from db.question import QuestionPool
|
||||
|
||||
class QuestionList:
|
||||
def __init__(self, cursor):
|
||||
self.cursor = cursor
|
||||
|
||||
def render(self, test_id = None):
|
||||
qp = QuestionPool(self.cursor)
|
||||
|
||||
if test_id:
|
||||
rendered_questions = [i.render_short() for i in qp.select_by_test_id(test_id)]
|
||||
else:
|
||||
rendered_questions = [i.render_short() for i in qp.iter()]
|
||||
|
||||
return "\n".join(rendered_questions)
|
|
@ -0,0 +1,15 @@
|
|||
from db.response_option import ResponseOptionPool
|
||||
|
||||
class ResponseOptionList:
|
||||
def __init__(self, cursor):
|
||||
self.cursor = cursor
|
||||
|
||||
def render(self, question_id = None):
|
||||
rop = ResponseOptionPool(self.cursor)
|
||||
|
||||
if question_id:
|
||||
rendered_response_options = [i.render_full() for i in rop.select_by_question_id(question_id)]
|
||||
else:
|
||||
rendered_response_options = [i.render_full() for i in rop.iter()]
|
||||
|
||||
return "\n".join(rendered_response_options)
|
|
@ -3,6 +3,10 @@ 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):
|
||||
|
@ -13,6 +17,15 @@ class View:
|
|||
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,
|
||||
"view-question": self.render_view_question,
|
||||
"create-response-option": self.render_create_response_option,
|
||||
}
|
||||
|
||||
def get_db_connection(self):
|
||||
if not self.db_connection:
|
||||
|
@ -49,29 +62,124 @@ class View:
|
|||
else:
|
||||
mode = "test-list"
|
||||
|
||||
if mode == "test-list":
|
||||
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()
|
||||
|
||||
elif mode == "create-test":
|
||||
header = f"<h2>Створити новий тест"
|
||||
subheader = "<i>Введіть властивості нового тесту нижче</i>"
|
||||
|
||||
content = f'''<form action="/create-test.py">
|
||||
<label for="name">Назва тесту:</label><br>
|
||||
<input type="text" name="name" placeholder="Введіть назву..." required>
|
||||
<input type="submit" value="Створити">
|
||||
</form>'''
|
||||
|
||||
else:
|
||||
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'])
|
||||
|
||||
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"><br>
|
||||
<input type="submit" value="Зберегти зміни">
|
||||
</form>'''
|
||||
|
||||
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'])
|
||||
|
||||
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
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import mariadb as mdb
|
||||
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 'test_id' in args:
|
||||
print("Content-Type: text/plain; charset=UTF-8\r\n\r\nВи не зазначили ідентифікатор тесту, до якого має залежати запитання\r\n")
|
||||
sys.exit(0)
|
||||
|
||||
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:
|
||||
args['mtime'] = 0
|
||||
|
||||
cur = db_connection.cursor()
|
||||
|
||||
try:
|
||||
cur.execute(f"INSERT INTO question ( title, mtime, tstID ) VALUES ( '{escape_sql_string(args['title'])}', {args['mtime']}, {args['test_id']} );")
|
||||
db_connection.commit()
|
||||
|
||||
cur.execute(f"SELECT id FROM question ORDER BY id DESC;")
|
||||
|
||||
new_id = iter(cur).__next__()[0]
|
||||
print(f"Location: /index.py?mode=view-question&id={new_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")
|
|
@ -0,0 +1,47 @@
|
|||
import mariadb as mdb
|
||||
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 'question_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)
|
||||
|
||||
if not 'mtime' in args:
|
||||
args['mtime'] = 0
|
||||
|
||||
cur = db_connection.cursor()
|
||||
|
||||
try:
|
||||
cur.execute(f"INSERT INTO response_option ( label, qstID, corct ) VALUES ( '{escape_sql_string(args['label'])}', {args['question_id']}, 0 );")
|
||||
db_connection.commit()
|
||||
|
||||
#cur.execute(f"SELECT id FROM response ORDER BY id DESC;")
|
||||
|
||||
#new_id = iter(cur).__next__()[0]
|
||||
print(f"Location: /index.py?mode=view-question&id={args['question_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")
|
|
@ -0,0 +1,40 @@
|
|||
import mariadb as mdb
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
|
||||
from httputils import parse_query
|
||||
|
||||
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 'name' 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"INSERT INTO test ( name ) VALUES ( '{args['name']}' );")
|
||||
db_connection.commit()
|
||||
|
||||
cur.execute(f"SELECT id FROM test ORDER BY id DESC;")
|
||||
|
||||
new_id = iter(cur).__next__()[0]
|
||||
print(f"Location: /index.py?mode=view-test&id={new_id}\r\n\r\n")
|
||||
except:
|
||||
print(f"Content-Type: text/plain\r\n\r\nНе вдалося створити новий тест\r\n")
|
|
@ -1,8 +1,162 @@
|
|||
:root {
|
||||
--yellow-gradient: linear-gradient(45deg, #ffe88d, #fff8b7);
|
||||
--yellow-gradient-bright: linear-gradient(45deg, #ffeba1, #fffacb);
|
||||
--blue-gradient-subtle: linear-gradient(45deg, #e7ebff, #e7efff);
|
||||
--blue-gradient-glassy: linear-gradient(45deg, #fff9, #fff9);
|
||||
--red-gradient: linear-gradient(45deg, #ffd2cc, #ffcccc);
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
background: var(--blue-gradient-subtle);
|
||||
}
|
||||
|
||||
body {
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
header {
|
||||
border: solid 2px;
|
||||
padding: 10px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
header .top-half, header .lower-half {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
header .top-half {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
header .lower-half input {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
header .top-half .view-test-id-tag {
|
||||
color: #333333;
|
||||
font-size: 16pt;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
header .top-half .view-test-main-tag {
|
||||
color: #000;
|
||||
font-size: 20pt;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
header .lower-half a.generic-button,
|
||||
header .lower-half a.sub-button,
|
||||
main * a.sub-button,
|
||||
main * a.scary-button
|
||||
{
|
||||
text-decoration: none;
|
||||
border-radius: 15px;
|
||||
color: #000;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
margin: 4px;
|
||||
margin-top: 0;
|
||||
padding: 10px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
header .lower-half a.generic-button {
|
||||
background: var(--yellow-gradient);
|
||||
}
|
||||
|
||||
header .lower-half a.generic-button:hover {
|
||||
background: var(--yellow-gradient-bright);
|
||||
}
|
||||
|
||||
header .lower-half a.sub-button,
|
||||
main * a.sub-button
|
||||
{
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
main * div.controls
|
||||
{
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
margin-top: 13px;
|
||||
grid-auto-columns: max-content;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
main * a.sub-button {
|
||||
}
|
||||
|
||||
main * a.scary-button
|
||||
{
|
||||
background: var(--red-gradient);
|
||||
color: #500;
|
||||
}
|
||||
|
||||
main .test-short,
|
||||
main .question-short,
|
||||
main .response-option
|
||||
{
|
||||
padding: 20px;
|
||||
background: var(--blue-gradient-glassy);
|
||||
margin-top: 16px;
|
||||
border-radius: 14px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
main .test-short a.test-link,
|
||||
main .question-short a.question-link {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
main .test-short a.test-link .main-label {
|
||||
color: #002;
|
||||
font-weight: 700;
|
||||
font-size: 16pt;
|
||||
}
|
||||
|
||||
main .test-short a.test-link .sub-label,
|
||||
main .question-short a.question-link .sub-label {
|
||||
color: #333;
|
||||
margin-right: 11px;
|
||||
}
|
||||
|
||||
main .test-short a.test-link {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
main .question-short a.question-link .main-label {
|
||||
color: #002;
|
||||
font-weight: 600;
|
||||
font-size: 15pt;
|
||||
}
|
||||
|
||||
main * .sub-title {
|
||||
display: block;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
main .response-option a.response-option-mark {
|
||||
font-size: 16pt;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
padding: 2px 10px 3px 10px;
|
||||
margin-right: 12px;
|
||||
color: #001;
|
||||
border-radius: 24px;
|
||||
border: solid 1px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import mariadb as mdb
|
||||
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 'question_id' in args:
|
||||
print("Content-Type: text/plain; charset=UTF-8\r\n\r\nВи не зазначили ідентифікатор тесту, до якого має залежати запитання\r\n")
|
||||
sys.exit(0)
|
||||
|
||||
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 or not args['mtime']:
|
||||
args['mtime'] = 0
|
||||
|
||||
cur = db_connection.cursor()
|
||||
|
||||
try:
|
||||
cur.execute(f"UPDATE question SET title = '{escape_sql_string(args['title'])}', mtime = {args['mtime']} WHERE id = {args['question_id']};")
|
||||
db_connection.commit()
|
||||
|
||||
#cur.execute(f"SELECT id FROM question ORDER BY id DESC;")
|
||||
|
||||
#new_id = iter(cur).__next__()[0]
|
||||
print(f"Location: /index.py?mode=view-question&id={args['question_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")
|
|
@ -0,0 +1,44 @@
|
|||
import mariadb as mdb
|
||||
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 'res_opt_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 corct, qstID FROM response_option WHERE id = {args['res_opt_id']};")
|
||||
data = iter(cur).__next__()
|
||||
new_correctness = not bool(data[0])
|
||||
|
||||
cur.execute(f"UPDATE response_option SET corct = {int(new_correctness)} WHERE id = {args['res_opt_id']};")
|
||||
db_connection.commit()
|
||||
|
||||
#cur.execute(f"SELECT id FROM response ORDER BY id DESC;")
|
||||
|
||||
#new_id = iter(cur).__next__()[0]
|
||||
print(f"Location: /index.py?mode=view-question&id={data[1]}\r\n\r\n")
|
||||
except Exception as e:
|
||||
print(f"Content-Type: text/plain; charset=UTF-8\r\n\r\nНе вдалося створити новий варіант відповіді ({e})\r\n")
|
|
@ -1,3 +1,11 @@
|
|||
html_escaping = {
|
||||
"<": "<",
|
||||
">": ">",
|
||||
"\"": """
|
||||
}
|
||||
|
||||
|
||||
|
||||
def decode_url(url):
|
||||
i = 0
|
||||
end = len(url)
|
||||
|
@ -14,6 +22,9 @@ def decode_url(url):
|
|||
i += 3
|
||||
except:
|
||||
i += 3
|
||||
elif url[i] == "+":
|
||||
decode_buffer += " "
|
||||
i += 1
|
||||
else:
|
||||
decode_buffer += url[i]
|
||||
i += 1
|
||||
|
@ -29,3 +40,12 @@ def parse_query(query):
|
|||
query_dict[decode_url(k)] = decode_url(v)
|
||||
|
||||
return query_dict
|
||||
|
||||
def escape_sql_string(s):
|
||||
return s.replace("'", "''")
|
||||
|
||||
def escape_html(s):
|
||||
for k, v in html_escaping.items():
|
||||
s = s.replace(k, v)
|
||||
|
||||
return s
|
||||
|
|
|
@ -1,43 +1,14 @@
|
|||
import sys
|
||||
import os
|
||||
print(f"PWD: {os.getcwd()}", file=sys.stderr)
|
||||
#print(f"PWD: {os.getcwd()}", file=sys.stderr)
|
||||
|
||||
print(f"Environ: {os.environ}", file=sys.stderr)
|
||||
#print(f"Environ: {os.environ}", file=sys.stderr)
|
||||
|
||||
sys.path.insert(0, "/root/ipz-server-1/server/cgi/")
|
||||
|
||||
from view import View
|
||||
from httputils import parse_query
|
||||
'''
|
||||
def decode_url(url):
|
||||
i = 0
|
||||
end = len(url)
|
||||
|
||||
decode_buffer = ''
|
||||
char_buffer = bytearray()
|
||||
|
||||
while i < end:
|
||||
if url[i] == '%':
|
||||
try:
|
||||
char_buffer.append(int(f'0x{url[i+1:i+3]}', 16))
|
||||
decode_buffer += char_buffer.decode("UTF-8")
|
||||
del char_buffer[:]
|
||||
i += 3
|
||||
except:
|
||||
i += 3
|
||||
else:
|
||||
decode_buffer += url[i]
|
||||
i += 1
|
||||
|
||||
return decode_buffer
|
||||
|
||||
query = [i for i in os.environ['QUERY_STRING'].split("&") if i]
|
||||
|
||||
query_dict = {}
|
||||
for i in query:
|
||||
k, v = i.split("=")
|
||||
query_dict[decode_url(k)] = decode_url(v)
|
||||
'''
|
||||
|
||||
query_dict = parse_query(os.environ['QUERY_STRING'])
|
||||
|
||||
|
|
Loading…
Reference in New Issue