import re
from templater import render_template
from utils import parse_cookies, add_text_headers, SUCCESS, BAD_REQUEST, NOT_FOUND, HTTP_METHODS
from config import TEXT_TEMPLATE_NAME
import db
_router_tree = {}
# url_format - регулярное выражение
def route(url_format, methods=None):
if methods is None:
methods = ['GET']
def wrapper(func):
def inner(url, query, *args, **kwargs):
pattern = re.compile(url_format)
match = re.fullmatch(pattern, url)
if match is None or len(match.groups()) != pattern.groups:
return BAD_REQUEST, '400 BAD REQUEST'
return func(query, *match.groups(), *args, **kwargs)
# Добавляем вызываемую функцию в дерево роутера.
# Благодаря этому указывать паттерн url и метод нужно указывать
# только в инициализаторе декоратора, а функция run сама разберется
# при каких условиях нужно вызвать конкретную функцию
_router_tree[url_format] = _router_tree.get(url_format, {})
for method in methods:
_router_tree[url_format][method] = inner
return inner
return wrapper
def run(request):
res = NOT_FOUND, NOT_FOUND
for key, value in request['cookies'].items():
db.set_cookie(key, value)
method, url = request['method'], request['url']
for url_pattern in _router_tree:
if re.fullmatch(url_pattern, url) and method in _router_tree[url_pattern]:
res = _router_tree[url_pattern][method](url, request['query'])
break
return add_text_headers(*res)
# По заданию любой метод, кроме GET и POST должны быть запрещены на сервере.
@route('/.*', list(set(HTTP_METHODS) ^ {'GET', 'POST'}))
def fallback_wrong_method(query, *args):
return NOT_FOUND, 'This method is not allowed'
@route('/')
def index_get(query, *args):
return SUCCESS, render_template('form', color=get_color())
# Хотелось попробовать сделать что-то высокоуровневое с декораторами.
# Если в этом коде есть какие-то серьезные проблемы, то скажите сразу.
@route(r'/div/(\d+)/to/(\d+)/?')
def divide_get(query, *args):
color = get_color()
try:
text = str(int(args[0]) / int(args[1]))
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, text=text, color=color)
except ZeroDivisionError as e:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('
' + str(e) if db.get_config_entry('show_errors') else '')
)
@route(r'/div/?', ['POST'])
def divide_post(query, *args):
color = get_color()
try:
text = str(int(query['numerator']) / int(query['denominator']))
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, text=text, color=color)
except KeyError:
field = 'числитель' if 'numerator' not in query else 'знаменатель'
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('
' + f'Указан неверный {field}')
)
except (ValueError, ZeroDivisionError) as e:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('
' + str(e) if db.get_config_entry('show_errors') else '')
)
@route(r'/show_errors/(\d{1})/?')
def show_errors_get(query, *args):
color = get_color()
if args[0] == '1':
db.set_config_entry('show_errors', 1)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция show_errors включена')
elif args[0] == '0':
db.set_config_entry('show_errors', 0)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция show_errors выключена')
else:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text='Опция show_errors не может принимать такое значение'
)
@route(r'/show_errors/?', ['POST'])
def show_errors_post(query, *args):
color = get_color()
if 'show_errors' not in query:
db.set_config_entry('show_errors', 0)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция show_errors выключена')
elif query['show_errors'] == '1':
db.set_config_entry('show_errors', 1)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция show_errors включена')
else:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text='Опция show_errors не может принимать такое значение'
)
@route(r'/set_cookie/=/(.*)/?')
def set_cookie_get(query, *args):
cookie_line = args[0]
color = get_color()
try:
cookies = parse_cookies(cookie_line)
for key, value in cookies.items():
db.set_cookie(key, value)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Cookie-файл обновлен')
except ValueError as e:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('
' + str(e) if db.get_config_entry('show_errors') else '')
)
@route(r'/set_cookie/=/?', ['POST'])
def set_cookie_post(query, *args):
color = get_color()
try:
cookie_line = query['cookie_line']
cookies = parse_cookies(cookie_line)
for key, value in cookies.items():
db.set_cookie(key, value)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Cookie-файл обновлен')
except KeyError:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('
' + f'Не указана строка с cookie')
)
except ValueError as e:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('
' + str(e) if db.get_config_entry('show_errors') else '')
)
@route(r'/short_log/(\d{1})/?')
def short_log_get(query, *args):
color = get_color()
if args[0] == '1':
db.set_config_entry('short_log', 1)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция short_log включена')
elif args[0] == '0':
db.set_config_entry('short_log', 0)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция short_log выключена')
else:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text='Опция short_log не может принимать такое значение'
)
@route(r'/short_log/?', ['POST'])
def short_log_post(query, *args):
color = get_color()
if 'short_log' not in query:
db.set_config_entry('short_log', 0)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция short_log выключена')
elif query['short_log'] == '1':
db.set_config_entry('short_log', 1)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция short_log включена')
else:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text='Опция short_log не может принимать такое значение'
)
def get_color():
color = db.get_cookie('bg_color', 'white')
if color not in ['green', 'white']:
color = 'white'
return color