RFCartography/rfcartography/search.py
2023-01-03 14:42:54 +01:00

120 lines
5.2 KiB
Python

from flask import Blueprint, abort, request, current_app, render_template
from rfcartography.index_parser import DocType, Document
def validate_type(user_input: str | None) -> DocType:
"""check if the given input is a DocType
return the DocType if it is valid
abort with HTTP Status 400 if it isn't valid"""
if user_input is None:
abort(400)
try:
doctype: DocType = DocType[user_input.upper()]
except KeyError:
abort(400)
return doctype
def validate_int(user_input: str | None) -> int:
"""check if the given input is a integer
return the int if it is valid
abort with HTTP Status 400 if it isn't valid"""
if user_input is None:
abort(400)
try:
i: int = int(user_input)
except ValueError:
abort(400)
return i
def validate_color(user_input: str) -> str:
"""check if the given user input is a valid color
return the string if it is valid
abort with HTTP Status 400 if it isn't valid"""
if user_input[0] != '#' or len(user_input) != 7:
abort(400)
for i in range(1,7):
if user_input[i] not in '0123456789abcdefABCDEF':
abort(400)
return user_input
def validate_linestyle(user_input: str) -> str:
"""check if the given user input is a valid linestyle
return the string if it is valid
abort with HTTP Status 400 if it isn't valid"""
if user_input in ['solid', 'dashed', 'dashdot', 'dotted', 'none']:
return user_input
else:
abort(400)
search: Blueprint = Blueprint('search', __name__)
@search.route('/', methods=['GET'])
def provide_searchform() -> tuple[str, int]:
"""handle requests for the search form"""
return render_template('search.html'), 200
@search.route('/map', methods= ['GET'])
def handle_search_request() -> tuple[str, int]:
"""handle search requests"""
params: dict = {}
doctype: DocType = validate_type(request.args.get('type', None))
num: int = validate_int(request.args.get('num', None))
depth: int = validate_int(request.args.get('depth', current_app.config['DEPTH_DEFAULT']))
nodes: list[DocType] = request.args.getlist('nodes_enabled', validate_type)
if nodes == []:
nodes = [DocType.RFC, DocType.STD, DocType.BCP, DocType.FYI,
DocType.NIC, DocType.IEN, DocType.RTR]
params['node_types'] = nodes
node_colors: dict[DocType, str | None] = {DocType.RFC: request.args.get('rfc_color', None),
DocType.STD: request.args.get('std_color', None),
DocType.BCP: request.args.get('bcp_color', None),
DocType.FYI: request.args.get('fyi_color', None),
DocType.NIC: request.args.get('nic_color', None),
DocType.IEN: request.args.get('ien_color', None),
DocType.RTR: request.args.get('rtr_color', None)}
if not all(color is None for color in node_colors.values()):
for nodetype in node_colors:
node_colors[nodetype] = validate_color(node_colors[nodetype])
params['node_color'] = node_colors
edge_style: dict[str, tuple[str, str]] = \
{'obsoletes': (request.args.get('obsoletes_style', None),
request.args.get('obsoletes_color', None)),
'obsoleted by': (request.args.get('obsoleted_by_style', None),
request.args.get('obsoleted_by_color', None)),
'updates': (request.args.get('updates_style', None),
request.args.get('updates_color', None)),
'updated by': (request.args.get('updated_by_style', None),
request.args.get('updated_by_color', None)),
'is also': (request.args.get('is_also_style', None),
request.args.get('is_also_color', None)),
'see also': (request.args.get('see_also_style', None),
request.args.get('see_also_color', None))}
if not all(arg is None for edge_type in edge_style.values() for arg in edge_type):
for edge_type in edge_style:
edge_style[edge_type] = (validate_linestyle(edge_style[edge_type][0]),
validate_color(edge_style[edge_type][1]))
params['edge_style'] = edge_style
url: str = "http://" + current_app.config['SERVER_NAME']
if url[-1] != '/':
url = url + '/'
doc: Document = current_app.cartographer.get_document(doctype, num)
if doc is None:
abort(404)
else:
rfc_map: RFCMap = current_app.cartographer.map_subnet(doc, url, depth, **params)
content: dict = {'core_node_id': doc.docID(),
'map': rfc_map.draw(),
'nodes': nodes,
'node_colors': rfc_map.get_node_colors(),
'edge_style': rfc_map.get_edge_styles()}
if not doctype in nodes:
content['nodes'].append(doctype)
return render_template('map.html', **content), 200