Commit b0b4aa81 authored by Robin Sonnabend's avatar Robin Sonnabend
Browse files

Require ADMIN_GROUP for deleting sensitive data

parent 3aa5cf16
......@@ -80,6 +80,7 @@ MAX_INDEX_DAYS = 14
# mail to contact in case of complex errors
ADMIN_MAIL = "admin@example.com"
ADMIN_GROUP = "admin"
# accept protocols even with some errors
# useful for importing old protocols
......
......@@ -107,6 +107,9 @@ class ProtocolType(db.Model):
def has_modify_right(self, user):
return (user is not None and self.modify_group != "" and self.modify_group in user.groups)
def has_admin_right(self, user):
return (user is not None and config.ADMIN_GROUP in user.groups)
@staticmethod
def get_modifiable_protocoltypes(user):
return [
......
......@@ -177,7 +177,8 @@ def new_type():
form.private_mail.data, form.public_mail.data,
form.use_wiki.data, form.wiki_category.data,
form.wiki_only_public.data, form.printer.data,
form.calendar.data)
form.calendar.data, form.restrict_networks.data,
form.allowed_networks.data)
db.session.add(protocoltype)
db.session.commit()
flash("Der Protokolltyp {} wurde angelegt.".format(protocoltype.name), "alert-success")
......@@ -224,6 +225,7 @@ def show_type(type_id):
@app.route("/type/delete/<int:type_id>")
@login_required
@group_required(config.ADMIN_GROUP)
def delete_type(type_id):
user = current_user()
protocoltype = ProtocolType.query.filter_by(id=type_id).first()
......@@ -279,6 +281,7 @@ def edit_reminder(type_id, reminder_id):
@app.route("/type/reminder/delete/<int:type_id>/<int:reminder_id>")
@login_required
@group_required(config.ADMIN_GROUP)
def delete_reminder(type_id, reminder_id):
protocoltype = ProtocolType.query.filter_by(id=type_id).first()
if protocoltype is None:
......@@ -521,6 +524,7 @@ def show_protocol(protocol_id):
@app.route("/protocol/delete/<int:protocol_id>")
@login_required
@group_required(config.ADMIN_GROUP)
def delete_protocol(protocol_id):
user = current_user()
protocol = Protocol.query.filter_by(id=protocol_id).first()
......@@ -1016,6 +1020,7 @@ def upload_document(protocol_id):
@app.route("/document/delete/<int:document_id>")
@login_required
@group_required(config.ADMIN_GROUP)
def delete_document(document_id):
user = current_user()
document = Document.query.filter_by(id=document_id).first()
......@@ -1177,6 +1182,7 @@ def edit_defaultmeta(meta_id):
@app.route("/defaultmeta/delete/<int:meta_id>")
@login_required
@group_required(config.ADMIN_GROUP)
def delete_defaultmeta(meta_id):
user = current_user()
meta = DefaultMeta.query.filter_by(id=meta_id).first()
......@@ -1186,8 +1192,8 @@ def delete_defaultmeta(meta_id):
name = meta.name
type_id = meta.protocoltype.id
db.session.delete(meta)
db.session.delete()
flash("Metadatenfeld '{}' gelöscht.", "alert-error")
db.session.commit()
flash("Metadatenfeld '{}' gelöscht.".format(name), "alert-error")
return redirect(request.args.get("next") or url_for("show_type", type_id=type_id))
@app.route("/login", methods=["GET", "POST"])
......
......@@ -111,15 +111,17 @@ def login_required(function):
return redirect(url_for("login", next=request.url))
return decorated_function
def group_required(function, group):
@wraps(function)
def decorated_function(*args, **kwargs):
if group in current_user.groups:
return function(*args, **kwargs)
else:
flash("You do not have the necessary permissions to view this page.")
return redirect(request.args.get("next") or url_for("index"))
return decorated_function
def group_required(group):
def decorator(function):
@wraps(function)
def decorated_function(*args, **kwargs):
if group in current_user().groups:
return function(*args, **kwargs)
else:
flash("You do not have the necessary permissions to view this page.")
return redirect(request.args.get("next") or url_for("index"))
return decorated_function
return decorator
DATE_KEY = "Datum"
START_TIME_KEY = "Beginn"
......
......@@ -8,6 +8,7 @@
{% set has_public_view_right = protocol.has_public_view_right(user) %}
{% set has_private_view_right = protocol.has_private_view_right(user) %}
{% set has_modify_right = protocol.has_modify_right(user) %}
{% set has_admin_right = protocol.protocoltype.has_admin_right(user) %}
{% block content %}
<div class="container">
......@@ -41,7 +42,9 @@
{% if protocol.has_compiled_document() %}
<a class="btn btn-success" href="{{url_for("download_document", document_id=protocol.get_compiled_document().id)}}">Download</a>
{% endif %}
<a class="btn btn-danger" href="{{url_for("delete_protocol", protocol_id=protocol.id)}}" onclick="return confirm('Bist du dir sicher, dass du das Protokoll {{protocol.get_identifier()}} löschen möchtest?');">Löschen</a>
{% if has_admin_right %}
<a class="btn btn-danger" href="{{url_for("delete_protocol", protocol_id=protocol.id)}}" onclick="return confirm('Bist du dir sicher, dass du das Protokoll {{protocol.get_identifier()}} löschen möchtest?');">Löschen</a>
{% endif %}
{% endif %}
</div>
{% endif %}
......
......@@ -81,7 +81,8 @@ class ProtocolsTable(Table):
if check_login():
if user is not None and protocol.protocoltype.has_private_view_right(user):
result.append(Table.link(url_for("show_type", type_id=protocol.protocoltype.id), protocol.protocoltype.short_name))
result.append(Table.link(url_for("delete_protocol", protocol_id=protocol.id), "Löschen", confirm="Bist du dir sicher, dass du das Protokoll {} löschen möchtest?".format(protocol.get_identifier())))
if protocol.protocoltype.has_admin_right(user):
result.append(Table.link(url_for("delete_protocol", protocol_id=protocol.id), "Löschen", confirm="Bist du dir sicher, dass du das Protokoll {} löschen möchtest?".format(protocol.get_identifier())))
else:
result.extend(["", ""])
return result
......@@ -131,6 +132,7 @@ class ProtocolTypeTable(SingleValueTable):
+ wiki_headers + calendar_headers + network_headers + action_headers)
def row(self):
user = current_user()
general_part = [
self.value.name,
self.value.short_name,
......@@ -165,6 +167,8 @@ class ProtocolTypeTable(SingleValueTable):
self.value.allowed_networks
]
action_part = [Table.link(url_for("delete_type", type_id=self.value.id), "Löschen", confirm="Bist du dir sicher, dass du den Protokolltype {} löschen möchtest?".format(self.value.name))]
if not self.value.has_admin_right(user):
action_part = [""]
return (general_part + mail_part + printing_part + wiki_part +
calendar_part + network_part + action_part)
......@@ -197,15 +201,19 @@ class MeetingRemindersTable(Table):
return ["Zeit", "Einladen", "Zusätzlicher Mailinhalt", ""]
def row(self, reminder):
return [
user = current_user()
general_part = [
"{} Tage".format(reminder.days_before),
self.get_send_summary(reminder),
reminder.additional_text or "",
Table.concat([
Table.link(url_for("edit_reminder", type_id=self.protocoltype.id, reminder_id=reminder.id), "Ändern"),
Table.link(url_for("delete_reminder", type_id=self.protocoltype.id, reminder_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))
])
reminder.additional_text or ""
]
action_links = [
Table.link(url_for("edit_reminder", type_id=self.protocoltype.id, reminder_id=reminder.id), "Ändern"),
]
if self.protocoltype.has_admin_right(user):
action_links.append(Table.link(url_for("delete_reminder", type_id=self.protocoltype.id, reminder_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)]
return general_part + action_part
def get_send_summary(self, reminder):
parts = []
......@@ -333,15 +341,15 @@ class DocumentsTable(Table):
def row(self, document):
user = current_user()
links = [Table.link(url_for("delete_document", document_id=document.id), "Löschen", confirm="Bist du dir sicher, dass du das Dokument {} löschen willst?".format(document.name))]
if config.PRINTING_ACTIVE:
links = []
if config.PRINTING_ACTIVE and document.protocol.has_modify_right(user):
links.append(Table.link(url_for("print_document", document_id=document.id), "Drucken"))
if document.protocol.protocoltype.has_admin_right(user):
links.append(Table.link(url_for("delete_document", document_id=document.id), "Löschen", confirm="Bist du dir sicher, dass du das Dokument {} löschen willst?".format(document.name)))
return [
document.id,
Table.link(url_for("download_document", document_id=document.id), document.name),
Table.concat(links)
if document.protocol.protocoltype.has_modify_right(user)
else ""
]
class TodoMailsTable(Table):
......@@ -373,11 +381,16 @@ class DefaultMetasTable(Table):
return ["Name", "Key", ""]
def row(self, meta):
return [
user = current_user()
general_part = [
meta.name,
meta.key,
Table.concat([
Table.link(url_for("edit_defaultmeta", meta_id=meta.id), "Ändern"),
Table.link(url_for("delete_defaultmeta", meta_id=meta.id, confirm="Bist du dir sicher, dass du das Metadatenfeld {} löschen willst?".format(meta.name)), "Löschen")
])
]
links = [
Table.link(url_for("edit_defaultmeta", meta_id=meta.id), "Ändern")
]
if meta.protocoltype.has_admin_right(user):
links.append(Table.link(url_for("delete_defaultmeta", meta_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)]
return general_part + link_part
Markdown is supported
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