Commit 0795452a authored by Robin Sonnabend's avatar Robin Sonnabend
Browse files

Search and fix misleading url_fors

parent f5a055fc
#!/usr/bin/env python3
import regex as re
import os
import sys
ROUTE_PATTERN = r'@(?:[[:alpha:]])+\.route\(\"(?<url>[^"]+)"[^)]*\)\s*(?:@[[:alpha:]_()., ]+\s*)*def\s+(?<name>[[:alpha:]][[:alnum:]_]*)\((?<params>[[:alnum:], ]*)\):'
quote_group = "[\"']"
URL_FOR_PATTERN = r'url_for\({quotes}(?<name>[[:alpha:]][[:alnum:]_]*){quotes}'.format(quotes=quote_group)
ROOT_DIR = "."
ENDINGS = [".py", ".html", ".txt"]
MAX_DEPTH = 2
def list_dir(dir, level=0):
if level >= MAX_DEPTH:
return
for file in os.listdir(dir):
path = os.path.join(dir, file)
if os.path.isfile(path):
if file == sys.argv[0]:
continue
for ending in ENDINGS:
if file.endswith(ending):
yield path
elif os.path.isdir(path):
yield from list_dir(path, level+1)
class Route:
def __init__(self, file, name, parameters):
self.file = file
self.name = name
self.parameters = parameters
def __repr__(self):
return "Route({file}, {name}, {parameters})".format(
file=self.file, name=self.name, parameters=self.parameters)
def get_parameter_set(self):
return {parameter.name for parameter in self.parameters}
class Parameter:
def __init__(self, name, type=None):
self.name = name
self.type = type
def __repr__(self):
return "Parameter({name}, {type})".format(name=self.name, type=self.type)
@staticmethod
def from_string(text):
if ":" in text:
type, name = text.split(":", 1)
return Parameter(name, type)
return Parameter(text)
def split_url_parameters(url):
params = []
current_param = None
for char in url:
if current_param is None:
if char == "<":
current_param = ""
else:
if char == ">":
params.append(Parameter.from_string(current_param))
current_param = None
else:
current_param += char
return params
def split_function_parameters(parameters):
return list(map(str.strip, parameters.split(",")))
def read_url_for_parameters(content):
params = []
bracket_level = 1
current_param = None
for char in content:
if bracket_level == 0:
if current_param is not None:
params.append(current_param.split("=")[0].strip())
return params
if char == ",":
if current_param is not None:
params.append(current_param.split("=")[0].strip())
current_param = ""
else:
if current_param is not None:
current_param += char
if char == "(":
bracket_level += 1
elif char == ")":
bracket_level -= 1
class UrlFor:
def __init__(self, file, name, parameters):
self.file = file
self.name = name
self.parameters = parameters
def __repr__(self):
return "UrlFor(file={file}, name={name}, parameters={parameters})".format(
file=self.file, name=self.name, parameters=self.parameters)
routes = {}
url_fors = []
for file in list_dir(ROOT_DIR):
with open(file, "r") as infile:
content = infile.read()
for match in re.finditer(ROUTE_PATTERN, content):
name = match.group("name")
function_parameters = split_function_parameters(match.group("params"))
url_parameters = split_url_parameters(match.group("url"))
routes[name] = Route(file, name, url_parameters)
for match in re.finditer(URL_FOR_PATTERN, content):
name = match.group("name")
begin, end = match.span()
parameters = read_url_for_parameters(content[end:])
url_fors.append(UrlFor(file=file, name=name, parameters=parameters))
for url_for in url_fors:
if url_for.name not in routes:
print("Missing route '{}' (for url_for in '{}')".format(url_for.name, url_for.file))
continue
route = routes[url_for.name]
route_parameters = route.get_parameter_set()
url_parameters = set(url_for.parameters)
if len(route_parameters ^ url_parameters) > 0:
print("Parameters not matching for '{}' in '{}:'".format(url_for.name, url_for.file))
only_route = route_parameters - url_parameters
only_url = url_parameters - route_parameters
if len(only_route) > 0:
print("Only in route: {}".format(only_route))
if len(only_url) > 0:
print("Only in url: {}".format(only_url))
...@@ -350,7 +350,7 @@ def list_protocols(): ...@@ -350,7 +350,7 @@ def list_protocols():
protocoltype = None protocoltype = None
protocoltype_id = None protocoltype_id = None
try: try:
protocoltype_id = int(request.args.get("protocoltype")) protocoltype_id = int(request.args.get("protocoltype_id"))
except (ValueError, TypeError): except (ValueError, TypeError):
pass pass
search_term = request.args.get("search") search_term = request.args.get("search")
...@@ -456,7 +456,7 @@ def new_protocol(): ...@@ -456,7 +456,7 @@ def new_protocol():
db.session.commit() db.session.commit()
tasks.push_tops_to_calendar(protocol) tasks.push_tops_to_calendar(protocol)
return redirect(request.args.get("next") or url_for("show_protocol", protocol_id=protocol.id)) return redirect(request.args.get("next") or url_for("show_protocol", protocol_id=protocol.id))
type_id = request.args.get("type_id") type_id = request.args.get("protocoltype_id")
if type_id is not None: if type_id is not None:
form.protocoltype.data = type_id form.protocoltype.data = type_id
upload_form.protocoltype.data = type_id upload_form.protocoltype.data = type_id
...@@ -731,7 +731,7 @@ def list_todos(): ...@@ -731,7 +731,7 @@ def list_todos():
protocoltype = None protocoltype = None
protocoltype_id = None protocoltype_id = None
try: try:
protocoltype_id = int(request.args.get("protocoltype")) protocoltype_id = int(request.args.get("protocoltype_id"))
except (ValueError, TypeError): except (ValueError, TypeError):
pass pass
search_term = request.args.get("search") search_term = request.args.get("search")
...@@ -774,7 +774,7 @@ def list_todos(): ...@@ -774,7 +774,7 @@ def list_todos():
@login_required @login_required
def new_todo(): def new_todo():
user = current_user() user = current_user()
protocoltype_id = optional_int_arg("type_id") protocoltype_id = optional_int_arg("protocoltype_id")
protocol_id = optional_int_arg("protocol_id") protocol_id = optional_int_arg("protocol_id")
protocoltype = ProtocolType.query.filter_by(id=protocoltype_id).first() protocoltype = ProtocolType.query.filter_by(id=protocoltype_id).first()
protocol = Protocol.query.filter_by(id=protocol_id).first() protocol = Protocol.query.filter_by(id=protocol_id).first()
...@@ -819,7 +819,7 @@ def edit_todo(todo): ...@@ -819,7 +819,7 @@ def edit_todo(todo):
if form.validate_on_submit(): if form.validate_on_submit():
form.populate_obj(todo) form.populate_obj(todo)
db.session.commit() db.session.commit()
return redirect(request.args.get("next") or url_for("list_todos", protocoltype=todo.protocoltype.id)) return redirect(request.args.get("next") or url_for("list_todos", protocoltype_id=todo.protocoltype.id))
return render_template("todo-edit.html", form=form, todo=todo) return render_template("todo-edit.html", form=form, todo=todo)
@app.route("/todo/show/<int:todo_id>") @app.route("/todo/show/<int:todo_id>")
...@@ -839,7 +839,7 @@ def delete_todo(todo): ...@@ -839,7 +839,7 @@ def delete_todo(todo):
db.session.delete(todo) db.session.delete(todo)
db.session.commit() db.session.commit()
flash("Todo gelöscht.", "alert-success") flash("Todo gelöscht.", "alert-success")
return redirect(request.args.get("next") or url_for("list_todos", protocoltype=type_id)) return redirect(request.args.get("next") or url_for("list_todos", protocoltype_id=type_id))
@app.route("/todo/merge", methods=["GET", "POST"]) @app.route("/todo/merge", methods=["GET", "POST"])
@login_required @login_required
...@@ -861,7 +861,7 @@ def merge_todos(): ...@@ -861,7 +861,7 @@ def merge_todos():
db.session.delete(todo2) db.session.delete(todo2)
db.session.commit() db.session.commit()
flash("Merged todos {} and {}.".format(id1, id2), "alert-success") flash("Merged todos {} and {}.".format(id1, id2), "alert-success")
return redirect(request.args.get("next") or url_for("show_todos")) return redirect(request.args.get("next") or url_for("list_todos"))
return render_template("todos-merge.html", form=form, next_url=request.args.get("next")) return render_template("todos-merge.html", form=form, next_url=request.args.get("next"))
@app.route("/decisions/list") @app.route("/decisions/list")
......
...@@ -4,6 +4,6 @@ ...@@ -4,6 +4,6 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
{{render_form(form, action_url=url_for("edit_default_top", type_id=protocoltype.id, defaulttop_id=defaulttop.id, next=url_for("show_type", protocoltype_id=protocoltype.id)), action_text="Ändern")}} {{render_form(form, action_url=url_for("edit_default_top", protocoltype_id=protocoltype.id, defaulttop_id=defaulttop.id, next=url_for("show_type", protocoltype_id=protocoltype.id)), action_text="Ändern")}}
</div> </div>
{% endblock %} {% endblock %}
...@@ -4,6 +4,6 @@ ...@@ -4,6 +4,6 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
{{render_form(form, action_url=url_for("new_default_top", type_id=protocoltype.id, next=url_for("show_type", protocoltype_id=protocoltype.id)), action_text="Anlegen")}} {{render_form(form, action_url=url_for("new_default_top", protocoltype_id=protocoltype.id, next=url_for("show_type", protocoltype_id=protocoltype.id)), action_text="Anlegen")}}
</div> </div>
{% endblock %} {% endblock %}
...@@ -4,6 +4,6 @@ ...@@ -4,6 +4,6 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
{{render_form(form, action_url=url_for("edit_defaultmeta", meta_id=meta.id, next=url_for("show_type", protocoltype_id=meta.protocoltype.id)), action_text="Ändern")}} {{render_form(form, action_url=url_for("edit_defaultmeta", defaultmeta_id=meta.id, next=url_for("show_type", protocoltype_id=meta.protocoltype.id)), action_text="Ändern")}}
</div> </div>
{% endblock %} {% endblock %}
...@@ -4,6 +4,6 @@ ...@@ -4,6 +4,6 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
{{render_form(form, action_url=url_for("edit_reminder", protocoltype_id=protocoltype.id, meetingreminder_id=meetingreminder.id, next=url_for("show_type", protocoltype_id=protocoltype.id)), action_text="Ändern")}} {{render_form(form, action_url=url_for("edit_reminder", meetingreminder_id=meetingreminder.id, next=url_for("show_type", protocoltype_id=protocoltype.id)), action_text="Ändern")}}
</div> </div>
{% endblock %} {% endblock %}
...@@ -124,7 +124,7 @@ class ProtocolTypesTable(Table): ...@@ -124,7 +124,7 @@ class ProtocolTypesTable(Table):
has_modify_right = protocoltype.has_modify_right(user) has_modify_right = protocoltype.has_modify_right(user)
protocoltype_link = url_for("show_type", protocoltype_id=protocoltype.id) protocoltype_link = url_for("show_type", protocoltype_id=protocoltype.id)
protocol_link = url_for("show_protocol", protocol_id=protocol.id) protocol_link = url_for("show_protocol", protocol_id=protocol.id)
new_protocol_link = url_for("new_protocol", type_id=protocoltype.id) new_protocol_link = url_for("new_protocol", protocoltype_id=protocoltype.id)
mobile_name = "{} ({})".format(protocoltype.name, protocoltype.short_name) mobile_name = "{} ({})".format(protocoltype.name, protocoltype.short_name)
mobile_links = [Table.link(protocol_link, protocol.get_identifier())] mobile_links = [Table.link(protocol_link, protocol.get_identifier())]
if has_modify_right: if has_modify_right:
...@@ -221,10 +221,10 @@ class DefaultTOPsTable(Table): ...@@ -221,10 +221,10 @@ class DefaultTOPsTable(Table):
top.name, top.name,
top.number, top.number,
Table.concat([ Table.concat([
Table.link(url_for("move_default_top", protocoltype_id=self.protocoltype.id, defaulttop_id=top.id, diff=1), "Runter"), Table.link(url_for("move_default_top", defaulttop_id=top.id, diff=1), "Runter"),
Table.link(url_for("move_default_top", protocoltype_id=self.protocoltype.id, defaulttop_id=top.id, diff=-1), "Hoch"), Table.link(url_for("move_default_top", defaulttop_id=top.id, diff=-1), "Hoch"),
Table.link(url_for("edit_default_top", protocoltype_id=self.protocoltype.id, defaulttop_id=top.id), "Ändern"), Table.link(url_for("edit_default_top", protocoltype_id=self.protocoltype.id, defaulttop_id=top.id), "Ändern"),
Table.link(url_for("delete_default_top", protocoltype_id=self.protocoltype.id, defaulttop_id=top.id), "Löschen", confirm="Bist du dir sicher, dass du den Standard-TOP {} löschen willst?".format(top.name)) Table.link(url_for("delete_default_top", defaulttop_id=top.id), "Löschen", confirm="Bist du dir sicher, dass du den Standard-TOP {} löschen willst?".format(top.name))
]) ])
] ]
...@@ -244,8 +244,8 @@ class MeetingRemindersTable(Table): ...@@ -244,8 +244,8 @@ class MeetingRemindersTable(Table):
reminder.additional_text or "" reminder.additional_text or ""
] ]
action_links = [ action_links = [
Table.link(url_for("edit_reminder", protocoltype_id=self.protocoltype.id, meetingreminder_id=reminder.id), "Ändern"), Table.link(url_for("edit_reminder", meetingreminder_id=reminder.id), "Ändern"),
Table.link(url_for("delete_reminder", protocoltype_id=self.protocoltype.id, meetingreminder_id=reminder.id), "Löschen", confirm="Bist du dir sicher, dass du die Einladungsmail {} Tage vor der Sitzung löschen willst?".format(reminder.days_before)) Table.link(url_for("delete_reminder", meetingreminder_id=reminder.id), "Löschen", confirm="Bist du dir sicher, dass du die Einladungsmail {} Tage vor der Sitzung löschen willst?".format(reminder.days_before))
] ]
action_part = [Table.concat(action_links)] action_part = [Table.concat(action_links)]
return general_part + action_part return general_part + action_part
...@@ -317,7 +317,7 @@ class TodosTable(Table): ...@@ -317,7 +317,7 @@ class TodosTable(Table):
todo.get_state(), todo.get_state(),
Table.link(url_for("show_protocol", protocol_id=protocol.id), protocol.get_identifier()) Table.link(url_for("show_protocol", protocol_id=protocol.id), protocol.get_identifier())
if protocol is not None if protocol is not None
else Table.link(url_for("list_protocols", protocoltype=todo.protocoltype.id), todo.protocoltype.short_name), else Table.link(url_for("list_protocols", protocoltype_id=todo.protocoltype.id), todo.protocoltype.short_name),
todo.who, todo.who,
todo.description, todo.description,
] ]
...@@ -437,7 +437,7 @@ class DefaultMetasTable(Table): ...@@ -437,7 +437,7 @@ class DefaultMetasTable(Table):
] ]
links = [ links = [
Table.link(url_for("edit_defaultmeta", defaultmeta_id=meta.id), "Ändern"), Table.link(url_for("edit_defaultmeta", defaultmeta_id=meta.id), "Ändern"),
Table.link(url_for("delete_defaultmeta", defaultmeta_id=meta.id, confirm="Bist du dir sicher, dass du das Metadatenfeld {} löschen willst?".format(meta.name)), "Löschen") Table.link(url_for("delete_defaultmeta", defaultmeta_id=meta.id), confirm="Bist du dir sicher, dass du das Metadatenfeld {} löschen willst?".format(meta.name), "Löschen")
] ]
link_part = [Table.concat(links)] link_part = [Table.concat(links)]
return general_part + link_part return general_part + link_part
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment