120 lines
5.2 KiB
Python
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
|
|
|
|
|